]>
Commit | Line | Data |
---|---|---|
86439e8d DS |
1 | #!/usr/bin/env python |
2 | ||
3 | # | |
4 | # test_pim.py | |
5 | # | |
6 | # Copyright (c) 2018 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 Cumulus Networks 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 | """ | |
25 | test_pim.py: Test pim | |
26 | """ | |
27 | ||
28 | import os | |
29 | import sys | |
30 | import pytest | |
12b76399 DS |
31 | import json |
32 | from functools import partial | |
86439e8d | 33 | |
7ed8fcff DS |
34 | pytestmark = pytest.mark.pimd |
35 | ||
86439e8d | 36 | CWD = os.path.dirname(os.path.realpath(__file__)) |
787e7624 | 37 | sys.path.append(os.path.join(CWD, "../")) |
86439e8d DS |
38 | |
39 | # pylint: disable=C0413 | |
40 | from lib import topotest | |
41 | from lib.topogen import Topogen, TopoRouter, get_topogen | |
42 | from lib.topolog import logger | |
43 | ||
86439e8d | 44 | |
6907ac7e | 45 | pytestmark = [pytest.mark.pimd] |
787e7624 | 46 | |
5980ad0a | 47 | |
e82b531d CH |
48 | def build_topo(tgen): |
49 | "Build function" | |
50 | ||
51 | for routern in range(1, 4): | |
52 | tgen.add_router("r{}".format(routern)) | |
53 | ||
54 | tgen.add_router("rp") | |
55 | ||
56 | # rp ------ r1 -------- r2 | |
57 | # \ | |
58 | # --------- r3 | |
59 | # r1 -> .1 | |
60 | # r2 -> .2 | |
61 | # rp -> .3 | |
62 | # r3 -> .4 | |
63 | # loopback network is 10.254.0.X/32 | |
64 | # | |
65 | # r1 <- sw1 -> r2 | |
66 | # r1-eth0 <-> r2-eth0 | |
67 | # 10.0.20.0/24 | |
68 | sw = tgen.add_switch("sw1") | |
69 | sw.add_link(tgen.gears["r1"]) | |
70 | sw.add_link(tgen.gears["r2"]) | |
71 | ||
72 | # r1 <- sw2 -> rp | |
73 | # r1-eth1 <-> rp-eth0 | |
74 | # 10.0.30.0/24 | |
75 | sw = tgen.add_switch("sw2") | |
76 | sw.add_link(tgen.gears["r1"]) | |
77 | sw.add_link(tgen.gears["rp"]) | |
78 | ||
79 | # 10.0.40.0/24 | |
80 | sw = tgen.add_switch("sw3") | |
81 | sw.add_link(tgen.gears["r1"]) | |
82 | sw.add_link(tgen.gears["r3"]) | |
787e7624 | 83 | |
7ed8fcff | 84 | |
86439e8d DS |
85 | def setup_module(mod): |
86 | "Sets up the pytest environment" | |
e82b531d | 87 | tgen = Topogen(build_topo, mod.__name__) |
86439e8d DS |
88 | tgen.start_topology() |
89 | ||
90 | # For all registered routers, load the zebra configuration file | |
e5f0ed14 | 91 | for rname, router in tgen.routers().items(): |
86439e8d | 92 | router.load_config( |
787e7624 | 93 | TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) |
86439e8d DS |
94 | ) |
95 | router.load_config( | |
787e7624 | 96 | TopoRouter.RD_PIM, os.path.join(CWD, "{}/pimd.conf".format(rname)) |
86439e8d | 97 | ) |
12b76399 | 98 | router.load_config( |
787e7624 | 99 | TopoRouter.RD_BGP, os.path.join(CWD, "{}/bgpd.conf".format(rname)) |
100 | ) | |
86439e8d DS |
101 | |
102 | # After loading the configurations, this function loads configured daemons. | |
103 | tgen.start_router() | |
787e7624 | 104 | # tgen.mininet_cli() |
86439e8d | 105 | |
86439e8d DS |
106 | |
107 | def teardown_module(mod): | |
108 | "Teardown the pytest environment" | |
109 | tgen = get_topogen() | |
110 | ||
111 | # This function tears down the whole topology. | |
112 | tgen.stop_topology() | |
113 | ||
787e7624 | 114 | |
12b76399 DS |
115 | def test_pim_rp_setup(): |
116 | "Ensure basic routing has come up and the rp has an outgoing interface" | |
787e7624 | 117 | # Ensure rp and r1 establish pim neighbor ship and bgp has come up |
118 | # Finally ensure that the rp has an outgoing interface on r1 | |
12b76399 DS |
119 | tgen = get_topogen() |
120 | ||
787e7624 | 121 | r1 = tgen.gears["r1"] |
122 | json_file = "{}/{}/rp-info.json".format(CWD, r1.name) | |
12b76399 DS |
123 | expected = json.loads(open(json_file).read()) |
124 | ||
787e7624 | 125 | test_func = partial( |
126 | topotest.router_json_cmp, r1, "show ip pim rp-info json", expected | |
127 | ) | |
12b76399 DS |
128 | _, result = topotest.run_and_expect(test_func, None, count=15, wait=5) |
129 | assertmsg = '"{}" JSON output mismatches'.format(r1.name) | |
130 | assert result is None, assertmsg | |
787e7624 | 131 | # tgen.mininet_cli() |
132 | ||
86439e8d DS |
133 | |
134 | def test_pim_send_mcast_stream(): | |
135 | "Establish a Multicast stream from r2 -> r1 and then ensure S,G is created as appropriate" | |
136 | logger.info("Establish a Mcast stream from r2->r1 and then ensure S,G created") | |
137 | ||
138 | tgen = get_topogen() | |
139 | ||
140 | if tgen.routers_have_failure(): | |
141 | pytest.skip(tgen.errors) | |
142 | ||
787e7624 | 143 | rp = tgen.gears["rp"] |
144 | r3 = tgen.gears["r3"] | |
145 | r2 = tgen.gears["r2"] | |
146 | r1 = tgen.gears["r1"] | |
86439e8d DS |
147 | |
148 | # Let's establish a S,G stream from r2 -> r1 | |
149 | CWD = os.path.dirname(os.path.realpath(__file__)) | |
787e7624 | 150 | r2.run( |
151 | "{}/mcast-tx.py --ttl 5 --count 5 --interval 10 229.1.1.1 r2-eth0 > /tmp/bar".format( | |
152 | CWD | |
153 | ) | |
154 | ) | |
c64d8d85 | 155 | # And from r3 -> r1 |
787e7624 | 156 | r3.run( |
157 | "{}/mcast-tx.py --ttl 5 --count 5 --interval 10 229.1.1.1 r3-eth0 > /tmp/bar".format( | |
158 | CWD | |
159 | ) | |
160 | ) | |
86439e8d DS |
161 | |
162 | # Let's see that it shows up and we have established some basic state | |
79d70a4c RZ |
163 | out = r1.vtysh_cmd("show ip pim upstream json", isjson=True) |
164 | expected = { | |
787e7624 | 165 | "229.1.1.1": { |
166 | "10.0.20.2": { | |
167 | "firstHopRouter": 1, | |
168 | "joinState": "NotJoined", | |
169 | "regState": "RegPrune", | |
170 | "inboundInterface": "r1-eth0", | |
79d70a4c RZ |
171 | } |
172 | } | |
173 | } | |
86439e8d | 174 | |
b4bee329 DS |
175 | test_func = partial( |
176 | topotest.router_json_cmp, r1, "show ip pim upstream json", expected | |
177 | ) | |
178 | _, result = topotest.run_and_expect(test_func, None, count=20, wait=1) | |
179 | assert result is None, "failed to converge pim" | |
787e7624 | 180 | # tgen.mininet_cli() |
181 | ||
12b76399 DS |
182 | |
183 | def test_pim_rp_sees_stream(): | |
184 | "Ensure that the RP sees the stream and has acted accordingly" | |
185 | tgen = get_topogen() | |
186 | ||
787e7624 | 187 | rp = tgen.gears["rp"] |
188 | json_file = "{}/{}/upstream.json".format(CWD, rp.name) | |
12b76399 | 189 | expected = json.loads(open(json_file).read()) |
86439e8d | 190 | |
787e7624 | 191 | test_func = partial( |
192 | topotest.router_json_cmp, rp, "show ip pim upstream json", expected | |
193 | ) | |
194 | _, result = topotest.run_and_expect(test_func, None, count=20, wait=0.5) | |
12b76399 DS |
195 | assertmsg = '"{}" JSON output mismatches'.format(rp.name) |
196 | assert result is None, assertmsg | |
86439e8d | 197 | |
787e7624 | 198 | |
86439e8d DS |
199 | def test_pim_igmp_report(): |
200 | "Send a igmp report from r2->r1 and ensure that the *,G state is created on r1" | |
201 | logger.info("Send a igmp report from r2-r1 and ensure *,G created") | |
202 | ||
203 | tgen = get_topogen() | |
204 | ||
205 | if tgen.routers_have_failure(): | |
206 | pytest.skip(tgen.errors) | |
207 | ||
787e7624 | 208 | r2 = tgen.gears["r2"] |
209 | r1 = tgen.gears["r1"] | |
86439e8d DS |
210 | |
211 | # Let's send a igmp report from r2->r1 | |
a53c08bc | 212 | cmd = [os.path.join(CWD, "mcast-rx.py"), "229.1.1.2", "r2-eth0"] |
8db751b8 CH |
213 | p = r2.popen(cmd) |
214 | try: | |
215 | expected = { | |
216 | "229.1.1.2": { | |
217 | "*": { | |
218 | "sourceIgmp": 1, | |
219 | "joinState": "Joined", | |
220 | "regState": "RegNoInfo", | |
221 | "sptBit": 0, | |
222 | } | |
79d70a4c RZ |
223 | } |
224 | } | |
8db751b8 CH |
225 | test_func = partial( |
226 | topotest.router_json_cmp, r1, "show ip pim upstream json", expected | |
227 | ) | |
a53c08bc | 228 | _, result = topotest.run_and_expect(test_func, None, count=5, wait=0.5) |
8db751b8 CH |
229 | assertmsg = '"{}" JSON output mismatches'.format(r1.name) |
230 | assert result is None, assertmsg | |
231 | finally: | |
232 | if p: | |
233 | p.terminate() | |
234 | p.wait() | |
86439e8d DS |
235 | |
236 | ||
237 | def test_memory_leak(): | |
238 | "Run the memory leak test and report results." | |
239 | tgen = get_topogen() | |
240 | if not tgen.is_memleak_enabled(): | |
787e7624 | 241 | pytest.skip("Memory leak test/report is disabled") |
86439e8d DS |
242 | |
243 | tgen.report_memory_leaks() | |
244 | ||
245 | ||
787e7624 | 246 | if __name__ == "__main__": |
86439e8d DS |
247 | args = ["-s"] + sys.argv[1:] |
248 | sys.exit(pytest.main(args)) |