]> git.proxmox.com Git - mirror_frr.git/blame - tests/topotests/zebra_rib/test_zebra_rib.py
tests: micronet: update infra
[mirror_frr.git] / tests / topotests / zebra_rib / test_zebra_rib.py
CommitLineData
abd2a1ff
DS
1#!/usr/bin/env python
2#
3# test_zebra_rib.py
4#
5# Copyright (c) 2019 by
6# Cumulus Networks, Inc
7# Donald Sharp
8#
9# Permission to use, copy, modify, and/or distribute this software
10# for any purpose with or without fee is hereby granted, provided
11# that the above copyright notice and this permission notice appear
12# in all copies.
13#
14# THE SOFTWARE IS PROVIDED "AS IS" AND NETDEF DISCLAIMS ALL WARRANTIES
15# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
16# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NETDEF BE LIABLE FOR
17# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY
18# DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
19# WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
20# ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
21# OF THIS SOFTWARE.
22#
23
24"""
25test_zebra_rib.py: Test some basic zebra <-> kernel interactions
26"""
27
28import os
29import re
30import sys
31from functools import partial
32import pytest
33import json
34
35# Save the Current Working Directory to find configuration files.
36CWD = os.path.dirname(os.path.realpath(__file__))
787e7624 37sys.path.append(os.path.join(CWD, "../"))
abd2a1ff
DS
38
39# pylint: disable=C0413
40# Import topogen and topotest helpers
41from lib import topotest
42from lib.topogen import Topogen, TopoRouter, get_topogen
43from lib.topolog import logger
fed16811 44from time import sleep
abd2a1ff
DS
45
46# Required to instantiate the topology builder class.
47from mininet.topo import Topo
48
9a47e7b2
DS
49pytestmark = [pytest.mark.sharpd]
50
787e7624 51
abd2a1ff
DS
52class ZebraTopo(Topo):
53 "Test topology builder"
787e7624 54
abd2a1ff
DS
55 def build(self, *_args, **_opts):
56 "Build function"
57 tgen = get_topogen(self)
58
787e7624 59 tgen.add_router("r1")
abd2a1ff
DS
60
61 # Create a empty network for router 1
787e7624 62 switch = tgen.add_switch("s1")
63 switch.add_link(tgen.gears["r1"])
64 switch.add_link(tgen.gears["r1"])
65 switch.add_link(tgen.gears["r1"])
66 switch.add_link(tgen.gears["r1"])
67 switch.add_link(tgen.gears["r1"])
68 switch.add_link(tgen.gears["r1"])
69 switch.add_link(tgen.gears["r1"])
70 switch.add_link(tgen.gears["r1"])
71
abd2a1ff
DS
72
73def setup_module(mod):
74 "Sets up the pytest environment"
75 tgen = Topogen(ZebraTopo, mod.__name__)
76 tgen.start_topology()
77
78 router_list = tgen.routers()
e5f0ed14 79 for rname, router in router_list.items():
abd2a1ff 80 router.load_config(
5980ad0a
DS
81 TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname))
82 )
fed16811 83 router.load_config(
5980ad0a
DS
84 TopoRouter.RD_SHARP, os.path.join(CWD, "{}/sharpd.conf".format(rname))
85 )
abd2a1ff
DS
86
87 # Initialize all routers.
88 tgen.start_router()
89
787e7624 90
abd2a1ff
DS
91def teardown_module(mod):
92 "Teardown the pytest environment"
93 tgen = get_topogen()
94 tgen.stop_topology()
95
787e7624 96
abd2a1ff
DS
97def test_zebra_kernel_admin_distance():
98 "Test some basic kernel routes added that should be accepted"
99 logger.info("Test some basic kernel routes that should be accepted")
100 tgen = get_topogen()
101 if tgen.routers_have_failure():
787e7624 102 pytest.skip("skipped because of router(s) failure")
abd2a1ff 103
787e7624 104 r1 = tgen.gears["r1"]
abd2a1ff
DS
105
106 # Route with 255/8192 metric
b604f586
CH
107
108 distance = 255
109 metric = 8192
110 def makekmetric(dist, metric):
111 return (dist << 24) + metric
112
113 r1.run("ip route add 4.5.1.0/24 via 192.168.210.2 dev r1-eth0 metric " + str(makekmetric(255, 8192)))
abd2a1ff 114 # Route with 1/1 metric
b604f586 115 r1.run("ip route add 4.5.2.0/24 via 192.168.211.2 dev r1-eth1 metric " + str(makekmetric(1, 1)))
abd2a1ff 116 # Route with 10/1 metric
b604f586 117 r1.run("ip route add 4.5.3.0/24 via 192.168.212.2 dev r1-eth2 metric " + str(makekmetric(10, 1)))
abd2a1ff 118 # Same route with a 160/1 metric
b604f586 119 r1.run("ip route add 4.5.3.0/24 via 192.168.213.2 dev r1-eth3 metric " + str(makekmetric(160, 1)))
abd2a1ff 120
787e7624 121 # Currently I believe we have a bug here with the same route and different
122 # metric. That needs to be properly resolved. Making a note for
123 # coming back around later and fixing this.
124 # tgen.mininet_cli()
abd2a1ff 125 for i in range(1, 2):
787e7624 126 json_file = "{}/r1/v4_route_{}.json".format(CWD, i)
abd2a1ff
DS
127 expected = json.loads(open(json_file).read())
128
787e7624 129 test_func = partial(
130 topotest.router_json_cmp,
131 r1,
132 "show ip route 4.5.{}.0 json".format(i),
133 expected,
134 )
ba002627 135 _, result = topotest.run_and_expect(test_func, None, count=20, wait=0.5)
abd2a1ff
DS
136 assertmsg = '"r1" JSON output mismatches'
137 assert result is None, assertmsg
787e7624 138 # tgen.mininet_cli()
139
abd2a1ff
DS
140
141def test_zebra_kernel_override():
142 "Test that a FRR route with a lower admin distance takes over"
143 logger.info("Test kernel override with a better admin distance")
144 tgen = get_topogen()
787e7624 145 if tgen.routers_have_failure():
5094b56d 146 pytest.skip("skipped because of previous test failure")
abd2a1ff 147
787e7624 148 r1 = tgen.gears["r1"]
abd2a1ff 149 r1.vtysh_cmd("conf\nip route 4.5.1.0/24 192.168.216.3")
787e7624 150 json_file = "{}/r1/v4_route_1_static_override.json".format(CWD)
abd2a1ff
DS
151 expected = json.loads(open(json_file).read())
152
787e7624 153 test_func = partial(
154 topotest.router_json_cmp, r1, "show ip route 4.5.1.0 json", expected
155 )
ba002627 156 _, result = topotest.run_and_expect(test_func, None, count=20, wait=0.5)
abd2a1ff
DS
157 assert result is None, '"r1" JSON output mismatches'
158
787e7624 159 logger.info(
160 "Test that the removal of the static route allows the kernel to take back over"
161 )
abd2a1ff 162 r1.vtysh_cmd("conf\nno ip route 4.5.1.0/24 192.168.216.3")
787e7624 163 json_file = "{}/r1/v4_route_1.json".format(CWD)
abd2a1ff
DS
164 expected = json.loads(open(json_file).read())
165
787e7624 166 test_func = partial(
167 topotest.router_json_cmp, r1, "show ip route 4.5.1.0 json", expected
168 )
ba002627 169 _, result = topotest.run_and_expect(test_func, None, count=20, wait=0.5)
abd2a1ff
DS
170 assert result is None, '"r1" JSON output mismatches'
171
5980ad0a 172
fed16811
DS
173def test_route_map_usage():
174 "Test that FRR only reruns over routes associated with the routemap"
175 logger.info("Test that FRR runs on selected re's on route-map changes")
176 tgen = get_topogen()
177 if tgen.routers_have_failure():
178 pytest.skip("Skipped because of previous test failure")
179
180 thisDir = os.path.dirname(os.path.realpath(__file__))
181
182 r1 = tgen.gears["r1"]
183 # set the delay timer to 1 to improve test coverage (HA)
184 r1.vtysh_cmd("conf\nzebra route-map delay-timer 1")
185 r1.vtysh_cmd("conf\nroute-map static permit 10\nset src 192.168.215.1")
186 r1.vtysh_cmd("conf\naccess-list 5 seq 5 permit 10.0.0.44/32")
187 r1.vtysh_cmd("conf\naccess-list 10 seq 5 permit 10.0.1.0/24")
5980ad0a
DS
188 r1.vtysh_cmd(
189 "conf\nroute-map sharp permit 10\nmatch ip address 10\nset src 192.168.214.1"
190 )
fed16811
DS
191 r1.vtysh_cmd("conf\nroute-map sharp permit 20\nset src 192.168.213.1")
192 r1.vtysh_cmd("conf\nip protocol static route-map static")
193 r1.vtysh_cmd("conf\nip protocol sharp route-map sharp")
194 sleep(4)
195 r1.vtysh_cmd("conf\nip route 10.100.100.100/32 192.168.216.3")
196 r1.vtysh_cmd("conf\nip route 10.100.100.101/32 10.0.0.44")
197 r1.vtysh_cmd("sharp install route 10.0.0.0 nexthop 192.168.216.3 500")
198 sleep(4)
199
200 static_rmapfile = "%s/r1/static_rmap.ref" % (thisDir)
201 expected = open(static_rmapfile).read().rstrip()
5980ad0a 202 expected = ("\n".join(expected.splitlines()) + "\n").rstrip()
5980ad0a
DS
203 logger.info(
204 "Does the show route-map static command run the correct number of times"
205 )
b604f586
CH
206 def check_static_map_correct_runs():
207 actual = r1.vtysh_cmd("show route-map static")
208 actual = ("\n".join(actual.splitlines()) + "\n").rstrip()
209 return topotest.get_textdiff(
210 actual,
211 expected,
212 title1="Actual Route-map output",
213 title2="Expected Route-map output",
214 )
215 ok, result = topotest.run_and_expect(check_static_map_correct_runs, "", count=5, wait=1)
216 assert ok, result
fed16811
DS
217
218 sharp_rmapfile = "%s/r1/sharp_rmap.ref" % (thisDir)
219 expected = open(sharp_rmapfile).read().rstrip()
5980ad0a 220 expected = ("\n".join(expected.splitlines()) + "\n").rstrip()
fed16811 221 logger.info("Does the show route-map sharp command run the correct number of times")
b604f586
CH
222 def check_sharp_map_correct_runs():
223 actual = r1.vtysh_cmd("show route-map sharp")
224 actual = ("\n".join(actual.splitlines()) + "\n").rstrip()
225 return topotest.get_textdiff(
226 actual,
227 expected,
228 title1="Actual Route-map output",
229 title2="Expected Route-map output",
230 )
231 ok, result = topotest.run_and_expect(check_sharp_map_correct_runs, "", count=5, wait=1)
232 assert ok, result
fed16811 233
5980ad0a
DS
234 logger.info(
235 "Add a extension to the static route-map to see the static route go away"
b604f586 236 " and test that the routes installed are correct"
5980ad0a 237 )
b604f586 238
fed16811 239 r1.vtysh_cmd("conf\nroute-map sharp deny 5\nmatch ip address 5")
fed16811
DS
240 # we are only checking the kernel here as that this will give us the implied
241 # testing of both the route-map and staticd withdrawing the route
242 # let's spot check that the routes were installed correctly
243 # in the kernel
fed16811
DS
244 sharp_ipfile = "%s/r1/iproute.ref" % (thisDir)
245 expected = open(sharp_ipfile).read().rstrip()
5980ad0a 246 expected = ("\n".join(expected.splitlines()) + "\n").rstrip()
b604f586
CH
247 def check_routes_installed():
248 actual = r1.run("ip route show")
249 actual = ("\n".join(actual.splitlines()) + "\n").rstrip()
250 actual = re.sub(r" nhid [0-9][0-9]", "", actual)
251 actual = re.sub(r" proto sharp", " proto XXXX", actual)
252 actual = re.sub(r" proto static", " proto XXXX", actual)
253 actual = re.sub(r" proto 194", " proto XXXX", actual)
254 actual = re.sub(r" proto 196", " proto XXXX", actual)
255 actual = re.sub(r" proto kernel", " proto XXXX", actual)
256 actual = re.sub(r" proto 2", " proto XXXX", actual)
257 # Some platforms have double spaces? Why??????
258 actual = re.sub(r" proto XXXX ", " proto XXXX ", actual)
259 actual = re.sub(r" metric", " metric", actual)
260 actual = re.sub(r" link ", " link ", actual)
261 return topotest.get_textdiff(
262 actual, expected, title1="Actual ip route show", title2="Expected ip route show"
263 )
264 ok, result = topotest.run_and_expect(check_routes_installed, "", count=5, wait=1)
265 assert ok, result
abd2a1ff 266
5980ad0a 267
abd2a1ff
DS
268def test_memory_leak():
269 "Run the memory leak test and report results."
270 tgen = get_topogen()
271 if not tgen.is_memleak_enabled():
787e7624 272 pytest.skip("Memory leak test/report is disabled")
abd2a1ff
DS
273
274 tgen.report_memory_leaks()
275
787e7624 276
277if __name__ == "__main__":
abd2a1ff
DS
278 args = ["-s"] + sys.argv[1:]
279 sys.exit(pytest.main(args))