]> git.proxmox.com Git - mirror_frr.git/blame - tests/topotests/pim_igmp_vrf/test_pim_vrf.py
Merge pull request #12798 from donaldsharp/rib_match_multicast
[mirror_frr.git] / tests / topotests / pim_igmp_vrf / test_pim_vrf.py
CommitLineData
51118489 1#!/usr/bin/env python
acddc0ed 2# SPDX-License-Identifier: ISC
51118489
MW
3
4#
5# test_pim_vrf.py
6# Part of NetDEF Topology Tests
7#
8# Copyright (c) 2020 by
9# Network Device Education Foundation, Inc. ("NetDEF")
10#
51118489
MW
11
12"""
13test_pim_vrf.py: Test PIM with VRFs.
14"""
15
d7d21c3a
CH
16# XXX clean up in later commit to avoid conflict on rebase
17# pylint: disable=C0413
18
51118489
MW
19# Tests PIM with VRF
20#
21# R1 is split into 2 VRF: Blue and Red, the others are normal
22# routers and Hosts
23# There are 2 similar topologies with overlapping IPs in each
a53c08bc 24# section.
51118489
MW
25#
26# Test steps:
27# - setup_module()
28# Create topology. Hosts are only using zebra/staticd,
29# no PIM, no OSPF (using IGMPv2 for multicast)
30# - test_ospf_convergence()
31# Wait for OSPF convergence in each VRF. OSPF is run on
32# R1, R11 and R12.
33# - test_pim_convergence()
34# Wait for PIM convergence in each VRF. PIM is run on
35# R1, R11 and R12. R11 is the RP for vrf blue, R12 is RP
36# for vrf red.
37# - test_vrf_pimreg_interfaces()
a53c08bc 38# Adding PIM RP in VRF information and verify pimreg
51118489
MW
39# interfaces in VRF blue and red
40# - test_mcast_vrf_blue()
a53c08bc 41# Start multicast stream for group 239.100.0.1 from Host
51118489
MW
42# H2 and join from Host H1 on vrf blue
43# Verify PIM JOIN status on R1 and R11
44# Stop multicast after verification
45# - test_mcast_vrf_red()
a53c08bc 46# Start multicast stream for group 239.100.0.1 from Host
51118489
MW
47# H4 and join from Host H3 on vrf blue
48# Verify PIM JOIN status on R1 and R12
49# Stop multicast after verification
50# - teardown_module(module)
51# shutdown topology
52#
53
54TOPOLOGY = """
55 +----------+
56 | Host H2 |
57 | Source |
58 +----------+
59 .2 |
60+---------+ +------------+ | +---------+
61| Host H1 | 192.168.100.0/24 | | .1 | .11 | Host H2 |
62| receive |------------------| VRF Blue |---------+--------| PIM RP |
63|IGMP JOIN| .10 .1 | | 192.168.101.0/24 | |
64+---------+ | | +---------+
65 =| = = R1 = = |=
66+---------+ | | +---------+
67| Host H3 | 192.168.100.0/24 | | 192.168.101.0/24 | Host H4 |
68| receive |------------------| VRF Red |---------+--------| PIM RP |
69|IGMP JOIN| .20 .1 | | .1 | .12 | |
70+---------+ +------------+ | +---------+
71 .4 |
72 +----------+
73 | Host H4 |
74 | Source |
75 +----------+
76"""
77
78import json
79import functools
80import os
81import sys
82import pytest
51118489
MW
83
84# Save the Current Working Directory to find configuration files.
85CWD = os.path.dirname(os.path.realpath(__file__))
86sys.path.append(os.path.join(CWD, "../"))
87
88# pylint: disable=C0413
89# Import topogen and topotest helpers
90from lib import topotest
91from lib.topogen import Topogen, TopoRouter, get_topogen
92from lib.topolog import logger
93from lib.topotest import iproute2_is_vrf_capable
a53c08bc 94from lib.common_config import required_linux_kernel_version
1973df1d 95from lib.pim import McastTesterHelper
51118489 96
51118489 97
4be92408 98pytestmark = [pytest.mark.ospfd, pytest.mark.pimd]
51118489
MW
99
100
1973df1d 101def build_topo(tgen):
a53c08bc 102 for hostNum in range(1, 5):
1973df1d
CH
103 tgen.add_router("h{}".format(hostNum))
104
105 # Create the main router
106 tgen.add_router("r1")
107
108 # Create the PIM RP routers
109 for rtrNum in range(11, 13):
110 tgen.add_router("r{}".format(rtrNum))
111
112 # Setup Switches and connections
113 for swNum in range(1, 5):
114 tgen.add_switch("sw{}".format(swNum))
115
116 ################
117 # 1st set of connections to routers for VRF red
118 ################
119
120 # Add connections H1 to R1 switch sw1
121 tgen.gears["h1"].add_link(tgen.gears["sw1"])
122 tgen.gears["r1"].add_link(tgen.gears["sw1"])
123
124 # Add connections R1 to R1x switch sw2
125 tgen.gears["r1"].add_link(tgen.gears["sw2"])
126 tgen.gears["h2"].add_link(tgen.gears["sw2"])
127 tgen.gears["r11"].add_link(tgen.gears["sw2"])
128
129 ################
130 # 2nd set of connections to routers for vrf blue
131 ################
132
133 # Add connections H1 to R1 switch sw1
134 tgen.gears["h3"].add_link(tgen.gears["sw3"])
135 tgen.gears["r1"].add_link(tgen.gears["sw3"])
136
137 # Add connections R1 to R1x switch sw2
138 tgen.gears["r1"].add_link(tgen.gears["sw4"])
139 tgen.gears["h4"].add_link(tgen.gears["sw4"])
140 tgen.gears["r12"].add_link(tgen.gears["sw4"])
51118489 141
a53c08bc 142
51118489
MW
143#####################################################
144#
145# Tests starting
146#
147#####################################################
148
a53c08bc 149
51118489
MW
150def setup_module(module):
151 logger.info("PIM IGMP VRF Topology: \n {}".format(TOPOLOGY))
152
1973df1d 153 tgen = Topogen(build_topo, module.__name__)
51118489
MW
154 tgen.start_topology()
155
c72e51ac
DS
156 # Required linux kernel version for this suite to run.
157 result = required_linux_kernel_version("4.19")
158 if result is not True:
159 pytest.skip("Kernel requirements are not met")
160
51118489
MW
161 vrf_setup_cmds = [
162 "ip link add name blue type vrf table 11",
163 "ip link add name red type vrf table 12",
164 "ip link set dev blue up",
165 "ip link set dev red up",
166 "ip link set dev r1-eth0 vrf blue up",
167 "ip link set dev r1-eth1 vrf blue up",
168 "ip link set dev r1-eth2 vrf red up",
169 "ip link set dev r1-eth3 vrf red up",
170 ]
171
172 # Starting Routers
173 router_list = tgen.routers()
174
175 # Create VRF on r2 first and add it's interfaces
176 for cmd in vrf_setup_cmds:
177 tgen.net["r1"].cmd(cmd)
178
179 for rname, router in router_list.items():
180 logger.info("Loading router %s" % rname)
181 router.load_config(
182 TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname))
183 )
a53c08bc 184 if rname[0] != "h":
51118489
MW
185 # Only load ospf on routers, not on end hosts
186 router.load_config(
187 TopoRouter.RD_OSPF, os.path.join(CWD, "{}/ospfd.conf".format(rname))
188 )
189 router.load_config(
190 TopoRouter.RD_PIM, os.path.join(CWD, "{}/pimd.conf".format(rname))
191 )
1973df1d 192
51118489
MW
193 tgen.start_router()
194
195
196def teardown_module(module):
197 tgen = get_topogen()
198 tgen.stop_topology()
51118489
MW
199
200
201def test_ospf_convergence():
202 "Test for OSPFv2 convergence"
203 tgen = get_topogen()
204
51118489
MW
205 # iproute2 needs to support VRFs for this suite to run.
206 if not iproute2_is_vrf_capable():
207 pytest.skip("Installed iproute2 version does not support VRFs")
208
209 # Skip if previous fatal error condition is raised
210 if tgen.routers_have_failure():
211 pytest.skip(tgen.errors)
212
213 logger.info("Checking OSPFv2 convergence on router r1 for VRF blue")
214
215 router = tgen.gears["r1"]
216 reffile = os.path.join(CWD, "r1/ospf_blue_neighbor.json")
217 expected = json.loads(open(reffile).read())
218
219 test_func = functools.partial(
a53c08bc
CH
220 topotest.router_json_cmp,
221 router,
222 "show ip ospf vrf blue neighbor json",
223 expected,
51118489
MW
224 )
225 _, res = topotest.run_and_expect(test_func, None, count=60, wait=2)
226 assertmsg = "OSPF router R1 did not converge on VRF blue"
227 assert res is None, assertmsg
228
229 logger.info("Checking OSPFv2 convergence on router r1 for VRF red")
230
231 router = tgen.gears["r1"]
232 reffile = os.path.join(CWD, "r1/ospf_red_neighbor.json")
233 expected = json.loads(open(reffile).read())
234
235 test_func = functools.partial(
236 topotest.router_json_cmp, router, "show ip ospf vrf red neighbor json", expected
237 )
238 _, res = topotest.run_and_expect(test_func, None, count=60, wait=2)
239 assertmsg = "OSPF router R1 did not converge on VRF red"
240 assert res is None, assertmsg
241
242
243def test_pim_convergence():
244 "Test for PIM convergence"
245 tgen = get_topogen()
246
247 # Skip if previous fatal error condition is raised
248 if tgen.routers_have_failure():
249 pytest.skip(tgen.errors)
250
251 logger.info("Checking PIM convergence on router r1 for VRF red")
252
253 router = tgen.gears["r1"]
254 reffile = os.path.join(CWD, "r1/pim_red_neighbor.json")
255 expected = json.loads(open(reffile).read())
256
257 test_func = functools.partial(
258 topotest.router_json_cmp, router, "show ip pim vrf red neighbor json", expected
259 )
260 _, res = topotest.run_and_expect(test_func, None, count=30, wait=2)
261 assertmsg = "PIM router R1 did not converge for VRF red"
262 assert res is None, assertmsg
263
264 logger.info("Checking PIM convergence on router r1 for VRF blue")
265
266 router = tgen.gears["r1"]
267 reffile = os.path.join(CWD, "r1/pim_blue_neighbor.json")
268 expected = json.loads(open(reffile).read())
269
270 test_func = functools.partial(
271 topotest.router_json_cmp, router, "show ip pim vrf blue neighbor json", expected
272 )
273 _, res = topotest.run_and_expect(test_func, None, count=30, wait=2)
274 assertmsg = "PIM router R1 did not converge for VRF blue"
275 assert res is None, assertmsg
276
277
278def test_vrf_pimreg_interfaces():
279 "Adding PIM RP in VRF information and verify pimreg interfaces"
280 tgen = get_topogen()
281
282 r1 = tgen.gears["r1"]
283 r1.vtysh_cmd("conf\ninterface blue\nip pim")
284 r1.vtysh_cmd("conf\nvrf blue\nip pim rp 192.168.0.11 239.100.0.1/32\nexit-vrf")
285
286 # Check pimreg11 interface on R1, VRF blue
287 reffile = os.path.join(CWD, "r1/pim_blue_pimreg11.json")
288 expected = json.loads(open(reffile).read())
289 test_func = functools.partial(
a53c08bc
CH
290 topotest.router_json_cmp,
291 r1,
292 "show ip pim vrf blue inter pimreg11 json",
293 expected,
51118489
MW
294 )
295 _, res = topotest.run_and_expect(test_func, None, count=5, wait=2)
296 assertmsg = "PIM router R1, VRF blue (table 11) pimreg11 interface missing or incorrect status"
297 assert res is None, assertmsg
298
299 r1.vtysh_cmd("conf\ninterface red\nip pim")
300 r1.vtysh_cmd("conf\nvrf red\nip pim rp 192.168.0.12 239.100.0.1/32\nexit-vrf")
301
302 # Check pimreg12 interface on R1, VRF red
303 reffile = os.path.join(CWD, "r1/pim_red_pimreg12.json")
304 expected = json.loads(open(reffile).read())
305 test_func = functools.partial(
a53c08bc
CH
306 topotest.router_json_cmp,
307 r1,
308 "show ip pim vrf red inter pimreg12 json",
309 expected,
51118489
MW
310 )
311 _, res = topotest.run_and_expect(test_func, None, count=5, wait=2)
312 assertmsg = "PIM router R1, VRF red (table 12) pimreg12 interface missing or incorrect status"
313 assert res is None, assertmsg
314
315
316##################################
317### Test PIM / IGMP with VRF
318##################################
319
a53c08bc 320
51118489
MW
321def check_mcast_entry(mcastaddr, pimrp, receiver, sender, vrf):
322 "Helper function to check RP"
323 tgen = get_topogen()
324
a53c08bc 325 logger.info("Testing PIM for VRF {} entry using {}".format(vrf, mcastaddr))
51118489 326
1973df1d
CH
327 with McastTesterHelper(tgen) as helper:
328 helper.run(sender, ["--send=0.7", mcastaddr, str(sender) + "-eth0"])
329 helper.run(receiver, [mcastaddr, str(receiver) + "-eth0"])
51118489 330
1973df1d 331 logger.info("mcast join and source for {} started".format(mcastaddr))
51118489 332
1973df1d
CH
333 router = tgen.gears["r1"]
334 reffile = os.path.join(CWD, "r1/pim_{}_join.json".format(vrf))
335 expected = json.loads(open(reffile).read())
51118489 336
1973df1d
CH
337 logger.info("verifying pim join on r1 for {} on VRF {}".format(mcastaddr, vrf))
338 test_func = functools.partial(
a53c08bc
CH
339 topotest.router_json_cmp,
340 router,
341 "show ip pim vrf {} join json".format(vrf),
342 expected,
1973df1d
CH
343 )
344 _, res = topotest.run_and_expect(test_func, None, count=10, wait=2)
345 assertmsg = "PIM router r1 did not show join status on VRF {}".format(vrf)
346 assert res is None, assertmsg
51118489 347
1973df1d
CH
348 logger.info("verifying pim join on PIM RP {} for {}".format(pimrp, mcastaddr))
349 router = tgen.gears[pimrp]
350 reffile = os.path.join(CWD, "{}/pim_{}_join.json".format(pimrp, vrf))
351 expected = json.loads(open(reffile).read())
51118489 352
1973df1d
CH
353 test_func = functools.partial(
354 topotest.router_json_cmp, router, "show ip pim join json", expected
355 )
356 _, res = topotest.run_and_expect(test_func, None, count=10, wait=2)
a53c08bc
CH
357 assertmsg = (
358 "PIM router {} did not get selected as the PIM RP for VRF {}".format(
359 pimrp, vrf
360 )
361 )
1973df1d 362 assert res is None, assertmsg
51118489
MW
363
364
365def test_mcast_vrf_blue():
366 "Test vrf blue with 239.100.0.1"
367 tgen = get_topogen()
368
369 # Skip if previous fatal error condition is raised
370 if tgen.routers_have_failure():
371 pytest.skip(tgen.errors)
372
a53c08bc 373 check_mcast_entry("239.100.0.1", "r11", "h1", "h2", "blue")
51118489
MW
374
375
376def test_mcast_vrf_red():
377 "Test vrf red with 239.100.0.1"
378 tgen = get_topogen()
379
380 # Skip if previous fatal error condition is raised
381 if tgen.routers_have_failure():
382 pytest.skip(tgen.errors)
383
a53c08bc 384 check_mcast_entry("239.100.0.1", "r12", "h3", "h4", "red")
51118489
MW
385
386
387if __name__ == "__main__":
388 args = ["-s"] + sys.argv[1:]
389 sys.exit(pytest.main(args))