]> git.proxmox.com Git - mirror_frr.git/blame - tests/topotests/zebra_rib/test_zebra_rib.py
tests: add pytest.mark.staticd for those tests missing it
[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
787e7624 49
abd2a1ff
DS
50class ZebraTopo(Topo):
51 "Test topology builder"
787e7624 52
abd2a1ff
DS
53 def build(self, *_args, **_opts):
54 "Build function"
55 tgen = get_topogen(self)
56
787e7624 57 tgen.add_router("r1")
abd2a1ff
DS
58
59 # Create a empty network for router 1
787e7624 60 switch = tgen.add_switch("s1")
61 switch.add_link(tgen.gears["r1"])
62 switch.add_link(tgen.gears["r1"])
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
abd2a1ff
DS
70
71def setup_module(mod):
72 "Sets up the pytest environment"
73 tgen = Topogen(ZebraTopo, mod.__name__)
74 tgen.start_topology()
75
76 router_list = tgen.routers()
e5f0ed14 77 for rname, router in router_list.items():
abd2a1ff 78 router.load_config(
5980ad0a
DS
79 TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname))
80 )
fed16811 81 router.load_config(
5980ad0a
DS
82 TopoRouter.RD_SHARP, os.path.join(CWD, "{}/sharpd.conf".format(rname))
83 )
abd2a1ff
DS
84
85 # Initialize all routers.
86 tgen.start_router()
87
787e7624 88
abd2a1ff
DS
89def teardown_module(mod):
90 "Teardown the pytest environment"
91 tgen = get_topogen()
92 tgen.stop_topology()
93
787e7624 94
abd2a1ff
DS
95def test_zebra_kernel_admin_distance():
96 "Test some basic kernel routes added that should be accepted"
97 logger.info("Test some basic kernel routes that should be accepted")
98 tgen = get_topogen()
99 if tgen.routers_have_failure():
787e7624 100 pytest.skip("skipped because of router(s) failure")
abd2a1ff 101
787e7624 102 r1 = tgen.gears["r1"]
abd2a1ff
DS
103
104 # Route with 255/8192 metric
787e7624 105 r1.run("ip route add 4.5.1.0/24 via 192.168.210.2 dev r1-eth0 metric 4278198272")
abd2a1ff 106 # Route with 1/1 metric
787e7624 107 r1.run("ip route add 4.5.2.0/24 via 192.168.211.2 dev r1-eth1 metric 16777217")
abd2a1ff 108 # Route with 10/1 metric
787e7624 109 r1.run("ip route add 4.5.3.0/24 via 192.168.212.2 dev r1-eth2 metric 167772161")
abd2a1ff 110 # Same route with a 160/1 metric
787e7624 111 r1.run("ip route add 4.5.3.0/24 via 192.168.213.2 dev r1-eth3 metric 2684354561")
abd2a1ff 112
787e7624 113 # Currently I believe we have a bug here with the same route and different
114 # metric. That needs to be properly resolved. Making a note for
115 # coming back around later and fixing this.
116 # tgen.mininet_cli()
abd2a1ff 117 for i in range(1, 2):
787e7624 118 json_file = "{}/r1/v4_route_{}.json".format(CWD, i)
abd2a1ff
DS
119 expected = json.loads(open(json_file).read())
120
787e7624 121 test_func = partial(
122 topotest.router_json_cmp,
123 r1,
124 "show ip route 4.5.{}.0 json".format(i),
125 expected,
126 )
127 _, result = topotest.run_and_expect(test_func, None, count=2, wait=0.5)
abd2a1ff
DS
128 assertmsg = '"r1" JSON output mismatches'
129 assert result is None, assertmsg
787e7624 130 # tgen.mininet_cli()
131
abd2a1ff
DS
132
133def test_zebra_kernel_override():
134 "Test that a FRR route with a lower admin distance takes over"
135 logger.info("Test kernel override with a better admin distance")
136 tgen = get_topogen()
787e7624 137 if tgen.routers_have_failure():
5094b56d 138 pytest.skip("skipped because of previous test failure")
abd2a1ff 139
787e7624 140 r1 = tgen.gears["r1"]
abd2a1ff 141 r1.vtysh_cmd("conf\nip route 4.5.1.0/24 192.168.216.3")
787e7624 142 json_file = "{}/r1/v4_route_1_static_override.json".format(CWD)
abd2a1ff
DS
143 expected = json.loads(open(json_file).read())
144
787e7624 145 test_func = partial(
146 topotest.router_json_cmp, r1, "show ip route 4.5.1.0 json", expected
147 )
148 _, result = topotest.run_and_expect(test_func, None, count=2, wait=0.5)
abd2a1ff
DS
149 assert result is None, '"r1" JSON output mismatches'
150
787e7624 151 logger.info(
152 "Test that the removal of the static route allows the kernel to take back over"
153 )
abd2a1ff 154 r1.vtysh_cmd("conf\nno ip route 4.5.1.0/24 192.168.216.3")
787e7624 155 json_file = "{}/r1/v4_route_1.json".format(CWD)
abd2a1ff
DS
156 expected = json.loads(open(json_file).read())
157
787e7624 158 test_func = partial(
159 topotest.router_json_cmp, r1, "show ip route 4.5.1.0 json", expected
160 )
161 _, result = topotest.run_and_expect(test_func, None, count=2, wait=0.5)
abd2a1ff
DS
162 assert result is None, '"r1" JSON output mismatches'
163
5980ad0a 164
fed16811
DS
165def test_route_map_usage():
166 "Test that FRR only reruns over routes associated with the routemap"
167 logger.info("Test that FRR runs on selected re's on route-map changes")
168 tgen = get_topogen()
169 if tgen.routers_have_failure():
170 pytest.skip("Skipped because of previous test failure")
171
172 thisDir = os.path.dirname(os.path.realpath(__file__))
173
174 r1 = tgen.gears["r1"]
175 # set the delay timer to 1 to improve test coverage (HA)
176 r1.vtysh_cmd("conf\nzebra route-map delay-timer 1")
177 r1.vtysh_cmd("conf\nroute-map static permit 10\nset src 192.168.215.1")
178 r1.vtysh_cmd("conf\naccess-list 5 seq 5 permit 10.0.0.44/32")
179 r1.vtysh_cmd("conf\naccess-list 10 seq 5 permit 10.0.1.0/24")
5980ad0a
DS
180 r1.vtysh_cmd(
181 "conf\nroute-map sharp permit 10\nmatch ip address 10\nset src 192.168.214.1"
182 )
fed16811
DS
183 r1.vtysh_cmd("conf\nroute-map sharp permit 20\nset src 192.168.213.1")
184 r1.vtysh_cmd("conf\nip protocol static route-map static")
185 r1.vtysh_cmd("conf\nip protocol sharp route-map sharp")
186 sleep(4)
187 r1.vtysh_cmd("conf\nip route 10.100.100.100/32 192.168.216.3")
188 r1.vtysh_cmd("conf\nip route 10.100.100.101/32 10.0.0.44")
189 r1.vtysh_cmd("sharp install route 10.0.0.0 nexthop 192.168.216.3 500")
190 sleep(4)
191
192 static_rmapfile = "%s/r1/static_rmap.ref" % (thisDir)
193 expected = open(static_rmapfile).read().rstrip()
5980ad0a 194 expected = ("\n".join(expected.splitlines()) + "\n").rstrip()
fed16811 195 actual = r1.vtysh_cmd("show route-map static")
5980ad0a
DS
196 actual = ("\n".join(actual.splitlines()) + "\n").rstrip()
197 logger.info(
198 "Does the show route-map static command run the correct number of times"
199 )
fed16811 200
5980ad0a
DS
201 diff = topotest.get_textdiff(
202 actual,
203 expected,
204 title1="Actual Route-map output",
205 title2="Expected Route-map output",
206 )
fed16811
DS
207 if diff:
208 logger.info("Actual:")
209 logger.info(actual)
210 logger.info("Expected:")
211 logger.info(expected)
212 srun = r1.vtysh_cmd("show run")
5980ad0a 213 srun = ("\n".join(srun.splitlines()) + "\n").rstrip()
fed16811
DS
214 logger.info("Show run")
215 logger.info(srun)
216 assert 0, "r1 static route processing:\n"
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 actual = r1.vtysh_cmd("show route-map sharp")
5980ad0a 222 actual = ("\n".join(actual.splitlines()) + "\n").rstrip()
fed16811
DS
223 logger.info("Does the show route-map sharp command run the correct number of times")
224
5980ad0a
DS
225 diff = topotest.get_textdiff(
226 actual,
227 expected,
228 title1="Actual Route-map output",
229 title2="Expected Route-map output",
230 )
fed16811
DS
231 if diff:
232 logger.info("Actual:")
233 logger.info(actual)
234 logger.info("Expected:")
235 logger.info(expected)
236 srun = r1.vtysh_cmd("show run")
5980ad0a 237 srun = ("\n".join(srun.splitlines()) + "\n").rstrip()
fed16811
DS
238 logger.info("Show run:")
239 logger.info(srun)
240 assert 0, "r1 sharp route-map processing:\n"
241
5980ad0a
DS
242 logger.info(
243 "Add a extension to the static route-map to see the static route go away"
244 )
fed16811
DS
245 r1.vtysh_cmd("conf\nroute-map sharp deny 5\nmatch ip address 5")
246 sleep(2)
247 # we are only checking the kernel here as that this will give us the implied
248 # testing of both the route-map and staticd withdrawing the route
249 # let's spot check that the routes were installed correctly
250 # in the kernel
251 logger.info("Test that the routes installed are correct")
252 sharp_ipfile = "%s/r1/iproute.ref" % (thisDir)
253 expected = open(sharp_ipfile).read().rstrip()
5980ad0a 254 expected = ("\n".join(expected.splitlines()) + "\n").rstrip()
fed16811 255 actual = r1.run("ip route show")
5980ad0a 256 actual = ("\n".join(actual.splitlines()) + "\n").rstrip()
fed16811
DS
257 actual = re.sub(r" nhid [0-9][0-9]", "", actual)
258 actual = re.sub(r" proto sharp", " proto XXXX", actual)
259 actual = re.sub(r" proto static", " proto XXXX", actual)
260 actual = re.sub(r" proto 194", " proto XXXX", actual)
261 actual = re.sub(r" proto 196", " proto XXXX", actual)
262 actual = re.sub(r" proto kernel", " proto XXXX", actual)
263 actual = re.sub(r" proto 2", " proto XXXX", actual)
264 # Some platforms have double spaces? Why??????
265 actual = re.sub(r" proto XXXX ", " proto XXXX ", actual)
266 actual = re.sub(r" metric", " metric", actual)
267 actual = re.sub(r" link ", " link ", actual)
5980ad0a
DS
268 diff = topotest.get_textdiff(
269 actual, expected, title1="Actual ip route show", title2="Expected ip route show"
270 )
fed16811
DS
271
272 if diff:
273 logger.info("Actual:")
274 logger.info(actual)
275 logger.info("Expected:")
276 logger.info(expected)
277 srun = r1.vtysh_cmd("show run")
5980ad0a 278 srun = ("\n".join(srun.splitlines()) + "\n").rstrip()
fed16811
DS
279 logger.info("Show run:")
280 logger.info(srun)
281 assert 0, "r1 ip route show is not correct:"
abd2a1ff 282
5980ad0a 283
abd2a1ff
DS
284def test_memory_leak():
285 "Run the memory leak test and report results."
286 tgen = get_topogen()
287 if not tgen.is_memleak_enabled():
787e7624 288 pytest.skip("Memory leak test/report is disabled")
abd2a1ff
DS
289
290 tgen.report_memory_leaks()
291
787e7624 292
293if __name__ == "__main__":
abd2a1ff
DS
294 args = ["-s"] + sys.argv[1:]
295 sys.exit(pytest.main(args))