blob: 6e9defd4c1dbbba11955684d23125413f27ddc32 [file] [log] [blame]
Renato Botelho do Coutoead1e532019-10-31 13:31:07 -05001#!/usr/bin/env python3
Jakub Grajciar7b867a82017-12-08 16:28:42 +01002
3import unittest
Jakub Grajciar7b867a82017-12-08 16:28:42 +01004
snaramre5d4b8912019-12-13 23:39:35 +00005from scapy.layers.l2 import Ether
6from scapy.packet import Raw
Paul Vinciguerraa279d9c2019-02-28 09:00:09 -08007from scapy.layers.inet import IP, IPOption
8from scapy.contrib.igmpv3 import IGMPv3, IGMPv3gr, IGMPv3mq, IGMPv3mr
9
Andrew Yourtchenko8dc0d482021-01-29 13:17:19 +000010from framework import tag_fixme_vpp_workers
Klement Sekerab23ffd72021-05-31 16:08:53 +020011from framework import VppTestCase, VppTestRunner
Klement Sekerad9b0c6f2022-04-26 19:02:15 +020012from vpp_igmp import (
13 find_igmp_state,
14 IGMP_FILTER,
15 IgmpRecord,
16 IGMP_MODE,
17 IgmpSG,
18 VppHostState,
19 wait_for_igmp_event,
20)
Neale Ranns947ea622018-06-07 23:48:20 -070021from vpp_ip_route import find_mroute, VppIpTable
22
23
24class IgmpMode:
25 HOST = 1
26 ROUTER = 0
Jakub Grajciar7b867a82017-12-08 16:28:42 +010027
28
Andrew Yourtchenko8dc0d482021-01-29 13:17:19 +000029@tag_fixme_vpp_workers
Jakub Grajciar7b867a82017-12-08 16:28:42 +010030class TestIgmp(VppTestCase):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +020031 """IGMP Test Case"""
Jakub Grajciar7b867a82017-12-08 16:28:42 +010032
Paul Vinciguerra7f9b7f92019-03-12 19:23:27 -070033 @classmethod
34 def setUpClass(cls):
35 super(TestIgmp, cls).setUpClass()
36
37 @classmethod
38 def tearDownClass(cls):
39 super(TestIgmp, cls).tearDownClass()
40
Jakub Grajciar7b867a82017-12-08 16:28:42 +010041 def setUp(self):
42 super(TestIgmp, self).setUp()
43
Neale Ranns947ea622018-06-07 23:48:20 -070044 self.create_pg_interfaces(range(4))
Jakub Grajciar7b867a82017-12-08 16:28:42 +010045 self.sg_list = []
46 self.config_list = []
47
48 self.ip_addr = []
Neale Ranns947ea622018-06-07 23:48:20 -070049 self.ip_table = VppIpTable(self, 1)
50 self.ip_table.add_vpp_config()
51
52 for pg in self.pg_interfaces[2:]:
53 pg.set_table_ip4(1)
Jakub Grajciar7b867a82017-12-08 16:28:42 +010054 for pg in self.pg_interfaces:
55 pg.admin_up()
56 pg.config_ip4()
57 pg.resolve_arp()
58
59 def tearDown(self):
60 for pg in self.pg_interfaces:
61 self.vapi.igmp_clear_interface(pg.sw_if_index)
62 pg.unconfig_ip4()
Neale Ranns947ea622018-06-07 23:48:20 -070063 pg.set_table_ip4(0)
Jakub Grajciar7b867a82017-12-08 16:28:42 +010064 pg.admin_down()
65 super(TestIgmp, self).tearDown()
66
67 def send(self, ti, pkts):
68 ti.add_stream(pkts)
69 self.pg_enable_capture(self.pg_interfaces)
70 self.pg_start()
71
Neale Ranns947ea622018-06-07 23:48:20 -070072 def test_igmp_flush(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +020073 """IGMP Link Up/down and Flush"""
Jakub Grajciar7b867a82017-12-08 16:28:42 +010074
75 #
Neale Ranns947ea622018-06-07 23:48:20 -070076 # FIX THIS. Link down.
Jakub Grajciar7b867a82017-12-08 16:28:42 +010077 #
Jakub Grajciar7b867a82017-12-08 16:28:42 +010078
Neale Ranns947ea622018-06-07 23:48:20 -070079 def test_igmp_enable(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +020080 """IGMP enable/disable on an interface
Jakub Grajciar7b867a82017-12-08 16:28:42 +010081
Klement Sekerad9b0c6f2022-04-26 19:02:15 +020082 check for the addition/removal of the IGMP mroutes"""
Jakub Grajciar7b867a82017-12-08 16:28:42 +010083
Neale Ranns947ea622018-06-07 23:48:20 -070084 self.vapi.igmp_enable_disable(self.pg0.sw_if_index, 1, IGMP_MODE.HOST)
85 self.vapi.igmp_enable_disable(self.pg1.sw_if_index, 1, IGMP_MODE.HOST)
Jakub Grajciar7b867a82017-12-08 16:28:42 +010086
Neale Ranns947ea622018-06-07 23:48:20 -070087 self.assertTrue(find_mroute(self, "224.0.0.1", "0.0.0.0", 32))
88 self.assertTrue(find_mroute(self, "224.0.0.22", "0.0.0.0", 32))
Jakub Grajciar7b867a82017-12-08 16:28:42 +010089
Neale Ranns947ea622018-06-07 23:48:20 -070090 self.vapi.igmp_enable_disable(self.pg2.sw_if_index, 1, IGMP_MODE.HOST)
91 self.vapi.igmp_enable_disable(self.pg3.sw_if_index, 1, IGMP_MODE.HOST)
Jakub Grajciar7b867a82017-12-08 16:28:42 +010092
Klement Sekerad9b0c6f2022-04-26 19:02:15 +020093 self.assertTrue(find_mroute(self, "224.0.0.1", "0.0.0.0", 32, table_id=1))
94 self.assertTrue(find_mroute(self, "224.0.0.22", "0.0.0.0", 32, table_id=1))
Neale Ranns947ea622018-06-07 23:48:20 -070095 self.vapi.igmp_enable_disable(self.pg0.sw_if_index, 0, IGMP_MODE.HOST)
96 self.vapi.igmp_enable_disable(self.pg1.sw_if_index, 0, IGMP_MODE.HOST)
97 self.vapi.igmp_enable_disable(self.pg2.sw_if_index, 0, IGMP_MODE.HOST)
98 self.vapi.igmp_enable_disable(self.pg3.sw_if_index, 0, IGMP_MODE.HOST)
Jakub Grajciar7b867a82017-12-08 16:28:42 +010099
Neale Ranns03c254e2020-03-17 14:25:10 +0000100 self.assertTrue(find_mroute(self, "224.0.0.1", "0.0.0.0", 32))
Neale Ranns947ea622018-06-07 23:48:20 -0700101 self.assertFalse(find_mroute(self, "224.0.0.22", "0.0.0.0", 32))
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200102 self.assertTrue(find_mroute(self, "224.0.0.1", "0.0.0.0", 32, table_id=1))
103 self.assertFalse(find_mroute(self, "224.0.0.22", "0.0.0.0", 32, table_id=1))
Jakub Grajciar7b867a82017-12-08 16:28:42 +0100104
105 def verify_general_query(self, p):
106 ip = p[IP]
Neale Ranns947ea622018-06-07 23:48:20 -0700107 self.assertEqual(len(ip.options), 1)
108 self.assertEqual(ip.options[0].option, 20)
Jakub Grajciar7b867a82017-12-08 16:28:42 +0100109 self.assertEqual(ip.dst, "224.0.0.1")
110 self.assertEqual(ip.proto, 2)
111 igmp = p[IGMPv3]
112 self.assertEqual(igmp.type, 0x11)
113 self.assertEqual(igmp.gaddr, "0.0.0.0")
114
Neale Ranns947ea622018-06-07 23:48:20 -0700115 def verify_group_query(self, p, grp, srcs):
116 ip = p[IP]
117 self.assertEqual(ip.dst, grp)
118 self.assertEqual(ip.proto, 2)
119 self.assertEqual(len(ip.options), 1)
120 self.assertEqual(ip.options[0].option, 20)
121 self.assertEqual(ip.proto, 2)
122 igmp = p[IGMPv3]
123 self.assertEqual(igmp.type, 0x11)
124 self.assertEqual(igmp.gaddr, grp)
Jakub Grajciar7b867a82017-12-08 16:28:42 +0100125
Neale Ranns947ea622018-06-07 23:48:20 -0700126 def verify_report(self, rx, records):
127 ip = rx[IP]
128 self.assertEqual(rx[IP].dst, "224.0.0.22")
129 self.assertEqual(len(ip.options), 1)
130 self.assertEqual(ip.options[0].option, 20)
131 self.assertEqual(ip.proto, 2)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200132 self.assertEqual(
133 IGMPv3.igmpv3types[rx[IGMPv3].type], "Version 3 Membership Report"
134 )
Neale Ranns947ea622018-06-07 23:48:20 -0700135 self.assertEqual(rx[IGMPv3mr].numgrp, len(records))
Jakub Grajciar7b867a82017-12-08 16:28:42 +0100136
Neale Ranns947ea622018-06-07 23:48:20 -0700137 received = rx[IGMPv3mr].records
Jakub Grajciar7b867a82017-12-08 16:28:42 +0100138
Neale Ranns947ea622018-06-07 23:48:20 -0700139 for ii in range(len(records)):
140 gr = received[ii]
141 r = records[ii]
142 self.assertEqual(IGMPv3gr.igmpv3grtypes[gr.rtype], r.type)
143 self.assertEqual(gr.numsrc, len(r.sg.saddrs))
144 self.assertEqual(gr.maddr, r.sg.gaddr)
145 self.assertEqual(len(gr.srcaddrs), len(r.sg.saddrs))
Jakub Grajciar7b867a82017-12-08 16:28:42 +0100146
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200147 self.assertEqual(sorted(gr.srcaddrs), sorted(r.sg.saddrs))
Jakub Grajciar7b867a82017-12-08 16:28:42 +0100148
Neale Ranns947ea622018-06-07 23:48:20 -0700149 def add_group(self, itf, sg, n_pkts=2):
150 self.pg_enable_capture(self.pg_interfaces)
151 self.pg_start()
Jakub Grajciar7b867a82017-12-08 16:28:42 +0100152
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200153 hs = VppHostState(self, IGMP_FILTER.INCLUDE, itf.sw_if_index, sg)
Neale Ranns947ea622018-06-07 23:48:20 -0700154 hs.add_vpp_config()
Jakub Grajciar7b867a82017-12-08 16:28:42 +0100155
Neale Ranns947ea622018-06-07 23:48:20 -0700156 capture = itf.get_capture(n_pkts, timeout=10)
Jakub Grajciar7b867a82017-12-08 16:28:42 +0100157
Neale Ranns947ea622018-06-07 23:48:20 -0700158 # reports are transmitted twice due to default rebostness value=2
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200159 self.verify_report(capture[0], [IgmpRecord(sg, "Allow New Sources")]),
160 self.verify_report(capture[1], [IgmpRecord(sg, "Allow New Sources")]),
Jakub Grajciar7b867a82017-12-08 16:28:42 +0100161
Neale Ranns947ea622018-06-07 23:48:20 -0700162 return hs
Jakub Grajciar7b867a82017-12-08 16:28:42 +0100163
Neale Ranns947ea622018-06-07 23:48:20 -0700164 def remove_group(self, hs):
165 self.pg_enable_capture(self.pg_interfaces)
166 self.pg_start()
167 hs.remove_vpp_config()
Jakub Grajciar7b867a82017-12-08 16:28:42 +0100168
Jakub Grajciar7b867a82017-12-08 16:28:42 +0100169 capture = self.pg0.get_capture(1, timeout=10)
170
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200171 self.verify_report(capture[0], [IgmpRecord(hs.sg, "Block Old Sources")])
Jakub Grajciar7b867a82017-12-08 16:28:42 +0100172
Neale Ranns947ea622018-06-07 23:48:20 -0700173 def test_igmp_host(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200174 """IGMP Host functions"""
Jakub Grajciar7b867a82017-12-08 16:28:42 +0100175
176 #
Neale Ranns947ea622018-06-07 23:48:20 -0700177 # Enable interface for host functions
Jakub Grajciar7b867a82017-12-08 16:28:42 +0100178 #
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200179 self.vapi.igmp_enable_disable(self.pg0.sw_if_index, 1, IGMP_MODE.HOST)
Jakub Grajciar7b867a82017-12-08 16:28:42 +0100180
Neale Ranns947ea622018-06-07 23:48:20 -0700181 #
182 # Add one S,G of state and expect a state-change event report
183 # indicating the addition of the S,G
184 #
185 h1 = self.add_group(self.pg0, IgmpSG("239.1.1.1", ["1.1.1.1"]))
Jakub Grajciar7b867a82017-12-08 16:28:42 +0100186
Neale Ranns947ea622018-06-07 23:48:20 -0700187 # search for the corresponding state created in VPP
188 dump = self.vapi.igmp_dump(self.pg0.sw_if_index)
189 self.assertEqual(len(dump), 1)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200190 self.assertTrue(find_igmp_state(dump, self.pg0, "239.1.1.1", "1.1.1.1"))
Jakub Grajciar7b867a82017-12-08 16:28:42 +0100191
Neale Ranns947ea622018-06-07 23:48:20 -0700192 #
193 # Send a general query (to the all router's address)
Neale Ranns01b0a052019-06-30 09:05:05 +0000194 # expect VPP to respond with a membership report.
195 # Pad the query with 0 - some devices in the big wild
196 # internet are prone to this.
Neale Ranns947ea622018-06-07 23:48:20 -0700197 #
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200198 p_g = (
199 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
200 / IP(src=self.pg0.remote_ip4, dst="224.0.0.1", tos=0xC0)
201 / IGMPv3(type="Membership Query", mrcode=100)
202 / IGMPv3mq(gaddr="0.0.0.0")
203 / Raw(b"\x00" * 10)
204 )
Neale Ranns947ea622018-06-07 23:48:20 -0700205
206 self.send(self.pg0, p_g)
207
208 capture = self.pg0.get_capture(1, timeout=10)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200209 self.verify_report(capture[0], [IgmpRecord(h1.sg, "Mode Is Include")])
Neale Ranns947ea622018-06-07 23:48:20 -0700210
211 #
212 # Group specific query
213 #
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200214 p_gs = (
215 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
216 / IP(
217 src=self.pg0.remote_ip4,
218 dst="239.1.1.1",
219 tos=0xC0,
220 options=[
221 IPOption(copy_flag=1, optclass="control", option="router_alert")
222 ],
223 )
224 / IGMPv3(type="Membership Query", mrcode=100)
225 / IGMPv3mq(gaddr="239.1.1.1")
226 )
Neale Ranns947ea622018-06-07 23:48:20 -0700227
228 self.send(self.pg0, p_gs)
229
230 capture = self.pg0.get_capture(1, timeout=10)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200231 self.verify_report(capture[0], [IgmpRecord(h1.sg, "Mode Is Include")])
Neale Ranns947ea622018-06-07 23:48:20 -0700232
233 #
234 # A group and source specific query, with the source matching
235 # the source VPP has
236 #
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200237 p_gs1 = (
238 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
239 / IP(
240 src=self.pg0.remote_ip4,
241 dst="239.1.1.1",
242 tos=0xC0,
243 options=[
244 IPOption(copy_flag=1, optclass="control", option="router_alert")
245 ],
246 )
247 / IGMPv3(type="Membership Query", mrcode=100)
248 / IGMPv3mq(gaddr="239.1.1.1", srcaddrs=["1.1.1.1"])
249 )
Neale Ranns947ea622018-06-07 23:48:20 -0700250
251 self.send(self.pg0, p_gs1)
252
253 capture = self.pg0.get_capture(1, timeout=10)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200254 self.verify_report(capture[0], [IgmpRecord(h1.sg, "Mode Is Include")])
Neale Ranns947ea622018-06-07 23:48:20 -0700255
256 #
Neale Ranns01b0a052019-06-30 09:05:05 +0000257 # A group and source specific query that reports more sources
258 # than the packet actually has.
259 #
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200260 p_gs2 = (
261 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
262 / IP(
263 src=self.pg0.remote_ip4,
264 dst="239.1.1.1",
265 tos=0xC0,
266 options=[
267 IPOption(copy_flag=1, optclass="control", option="router_alert")
268 ],
269 )
270 / IGMPv3(type="Membership Query", mrcode=100)
271 / IGMPv3mq(gaddr="239.1.1.1", numsrc=4, srcaddrs=["1.1.1.1"])
272 )
Neale Ranns01b0a052019-06-30 09:05:05 +0000273
274 self.send_and_assert_no_replies(self.pg0, p_gs2, timeout=10)
275
276 #
Neale Ranns947ea622018-06-07 23:48:20 -0700277 # A group and source specific query, with the source NOT matching
278 # the source VPP has. There should be no response.
279 #
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200280 p_gs2 = (
281 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
282 / IP(
283 src=self.pg0.remote_ip4,
284 dst="239.1.1.1",
285 tos=0xC0,
286 options=[
287 IPOption(copy_flag=1, optclass="control", option="router_alert")
288 ],
289 )
290 / IGMPv3(type="Membership Query", mrcode=100)
291 / IGMPv3mq(gaddr="239.1.1.1", srcaddrs=["1.1.1.2"])
292 )
Neale Ranns947ea622018-06-07 23:48:20 -0700293
294 self.send_and_assert_no_replies(self.pg0, p_gs2, timeout=10)
295
296 #
297 # A group and source specific query, with the multiple sources
298 # one of which matches the source VPP has.
299 # The report should contain only the source VPP has.
300 #
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200301 p_gs3 = (
302 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
303 / IP(
304 src=self.pg0.remote_ip4,
305 dst="239.1.1.1",
306 tos=0xC0,
307 options=[
308 IPOption(copy_flag=1, optclass="control", option="router_alert")
309 ],
310 )
311 / IGMPv3(type="Membership Query", mrcode=100)
312 / IGMPv3mq(gaddr="239.1.1.1", srcaddrs=["1.1.1.1", "1.1.1.2", "1.1.1.3"])
313 )
Neale Ranns947ea622018-06-07 23:48:20 -0700314
315 self.send(self.pg0, p_gs3)
316
317 capture = self.pg0.get_capture(1, timeout=10)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200318 self.verify_report(capture[0], [IgmpRecord(h1.sg, "Mode Is Include")])
Neale Ranns947ea622018-06-07 23:48:20 -0700319
320 #
Paul Vinciguerra8feeaff2019-03-27 11:25:48 -0700321 # Two source and group specific queries in quick succession, the
Neale Ranns947ea622018-06-07 23:48:20 -0700322 # first does not have VPPs source the second does. then vice-versa
323 #
324 self.send(self.pg0, [p_gs2, p_gs1])
325 capture = self.pg0.get_capture(1, timeout=10)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200326 self.verify_report(capture[0], [IgmpRecord(h1.sg, "Mode Is Include")])
Neale Ranns947ea622018-06-07 23:48:20 -0700327
328 self.send(self.pg0, [p_gs1, p_gs2])
329 capture = self.pg0.get_capture(1, timeout=10)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200330 self.verify_report(capture[0], [IgmpRecord(h1.sg, "Mode Is Include")])
Neale Ranns947ea622018-06-07 23:48:20 -0700331
332 #
333 # remove state, expect the report for the removal
334 #
335 self.remove_group(h1)
Jakub Grajciar7b867a82017-12-08 16:28:42 +0100336
337 dump = self.vapi.igmp_dump()
338 self.assertFalse(dump)
339
Neale Ranns947ea622018-06-07 23:48:20 -0700340 #
341 # A group with multiple sources
342 #
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200343 h2 = self.add_group(
344 self.pg0, IgmpSG("239.1.1.1", ["1.1.1.1", "1.1.1.2", "1.1.1.3"])
345 )
Neale Ranns947ea622018-06-07 23:48:20 -0700346
347 # search for the corresponding state created in VPP
348 dump = self.vapi.igmp_dump(self.pg0.sw_if_index)
349 self.assertEqual(len(dump), 3)
350 for s in h2.sg.saddrs:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200351 self.assertTrue(find_igmp_state(dump, self.pg0, "239.1.1.1", s))
Neale Ranns947ea622018-06-07 23:48:20 -0700352 #
353 # Send a general query (to the all router's address)
354 # expect VPP to respond with a membership report will all sources
355 #
356 self.send(self.pg0, p_g)
357
358 capture = self.pg0.get_capture(1, timeout=10)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200359 self.verify_report(capture[0], [IgmpRecord(h2.sg, "Mode Is Include")])
Neale Ranns947ea622018-06-07 23:48:20 -0700360
361 #
362 # Group and source specific query; some present some not
363 #
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200364 p_gs = (
365 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
366 / IP(
367 src=self.pg0.remote_ip4,
368 dst="239.1.1.1",
369 tos=0xC0,
370 options=[
371 IPOption(copy_flag=1, optclass="control", option="router_alert")
372 ],
373 )
374 / IGMPv3(type="Membership Query", mrcode=100)
375 / IGMPv3mq(gaddr="239.1.1.1", srcaddrs=["1.1.1.1", "1.1.1.2", "1.1.1.4"])
376 )
Neale Ranns947ea622018-06-07 23:48:20 -0700377
378 self.send(self.pg0, p_gs)
379
380 capture = self.pg0.get_capture(1, timeout=10)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200381 self.verify_report(
382 capture[0],
383 [
384 IgmpRecord(
385 IgmpSG("239.1.1.1", ["1.1.1.1", "1.1.1.2"]), "Mode Is Include"
386 )
387 ],
388 )
Neale Ranns947ea622018-06-07 23:48:20 -0700389
390 #
391 # add loads more groups
392 #
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200393 h3 = self.add_group(
394 self.pg0, IgmpSG("239.1.1.2", ["2.1.1.1", "2.1.1.2", "2.1.1.3"])
395 )
396 h4 = self.add_group(
397 self.pg0, IgmpSG("239.1.1.3", ["3.1.1.1", "3.1.1.2", "3.1.1.3"])
398 )
399 h5 = self.add_group(
400 self.pg0, IgmpSG("239.1.1.4", ["4.1.1.1", "4.1.1.2", "4.1.1.3"])
401 )
402 h6 = self.add_group(
403 self.pg0, IgmpSG("239.1.1.5", ["5.1.1.1", "5.1.1.2", "5.1.1.3"])
404 )
405 h7 = self.add_group(
406 self.pg0,
407 IgmpSG(
408 "239.1.1.6",
409 [
410 "6.1.1.1",
411 "6.1.1.2",
412 "6.1.1.3",
413 "6.1.1.4",
414 "6.1.1.5",
415 "6.1.1.6",
416 "6.1.1.7",
417 "6.1.1.8",
418 "6.1.1.9",
419 "6.1.1.10",
420 "6.1.1.11",
421 "6.1.1.12",
422 "6.1.1.13",
423 "6.1.1.14",
424 "6.1.1.15",
425 "6.1.1.16",
426 ],
427 ),
428 )
Neale Ranns947ea622018-06-07 23:48:20 -0700429
430 #
431 # general query.
432 # the order the groups come in is not important, so what is
433 # checked for is what VPP is sending today.
434 #
435 self.send(self.pg0, p_g)
436
437 capture = self.pg0.get_capture(1, timeout=10)
438
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200439 self.verify_report(
440 capture[0],
441 [
442 IgmpRecord(h3.sg, "Mode Is Include"),
443 IgmpRecord(h2.sg, "Mode Is Include"),
444 IgmpRecord(h6.sg, "Mode Is Include"),
445 IgmpRecord(h4.sg, "Mode Is Include"),
446 IgmpRecord(h5.sg, "Mode Is Include"),
447 IgmpRecord(h7.sg, "Mode Is Include"),
448 ],
449 )
Neale Ranns947ea622018-06-07 23:48:20 -0700450
451 #
452 # modify a group to add and remove some sources
453 #
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200454 h7.sg = IgmpSG(
455 "239.1.1.6",
456 [
457 "6.1.1.1",
458 "6.1.1.2",
459 "6.1.1.5",
460 "6.1.1.6",
461 "6.1.1.7",
462 "6.1.1.8",
463 "6.1.1.9",
464 "6.1.1.10",
465 "6.1.1.11",
466 "6.1.1.12",
467 "6.1.1.13",
468 "6.1.1.14",
469 "6.1.1.15",
470 "6.1.1.16",
471 "6.1.1.17",
472 "6.1.1.18",
473 ],
474 )
Neale Ranns947ea622018-06-07 23:48:20 -0700475
476 self.pg_enable_capture(self.pg_interfaces)
477 self.pg_start()
478 h7.add_vpp_config()
479
480 capture = self.pg0.get_capture(1, timeout=10)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200481 self.verify_report(
482 capture[0],
483 [
484 IgmpRecord(
485 IgmpSG("239.1.1.6", ["6.1.1.17", "6.1.1.18"]), "Allow New Sources"
486 ),
487 IgmpRecord(
488 IgmpSG("239.1.1.6", ["6.1.1.3", "6.1.1.4"]), "Block Old Sources"
489 ),
490 ],
491 )
Neale Ranns947ea622018-06-07 23:48:20 -0700492
493 #
494 # add an additional groups with many sources so that each group
495 # consumes the link MTU. We should therefore see multiple state
496 # state reports when queried.
497 #
498 self.vapi.sw_interface_set_mtu(self.pg0.sw_if_index, [560, 0, 0, 0])
499
500 src_list = []
501 for i in range(128):
502 src_list.append("10.1.1.%d" % i)
503
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200504 h8 = self.add_group(self.pg0, IgmpSG("238.1.1.1", src_list))
505 h9 = self.add_group(self.pg0, IgmpSG("238.1.1.2", src_list))
Neale Ranns947ea622018-06-07 23:48:20 -0700506
507 self.send(self.pg0, p_g)
508
509 capture = self.pg0.get_capture(4, timeout=10)
510
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200511 self.verify_report(
512 capture[0],
513 [
514 IgmpRecord(h3.sg, "Mode Is Include"),
515 IgmpRecord(h2.sg, "Mode Is Include"),
516 IgmpRecord(h6.sg, "Mode Is Include"),
517 IgmpRecord(h4.sg, "Mode Is Include"),
518 IgmpRecord(h5.sg, "Mode Is Include"),
519 ],
520 )
521 self.verify_report(capture[1], [IgmpRecord(h8.sg, "Mode Is Include")])
522 self.verify_report(capture[2], [IgmpRecord(h7.sg, "Mode Is Include")])
523 self.verify_report(capture[3], [IgmpRecord(h9.sg, "Mode Is Include")])
Neale Ranns947ea622018-06-07 23:48:20 -0700524
525 #
526 # drop the MTU further (so a 128 sized group won't fit)
527 #
528 self.vapi.sw_interface_set_mtu(self.pg0.sw_if_index, [512, 0, 0, 0])
529
530 self.pg_enable_capture(self.pg_interfaces)
531 self.pg_start()
532
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200533 h10 = VppHostState(
534 self,
535 IGMP_FILTER.INCLUDE,
536 self.pg0.sw_if_index,
537 IgmpSG("238.1.1.3", src_list),
538 )
Neale Ranns947ea622018-06-07 23:48:20 -0700539 h10.add_vpp_config()
540
541 capture = self.pg0.get_capture(2, timeout=10)
Andrew Yourtchenkocb265c62019-07-25 10:03:51 +0000542 # wait for a little bit
543 self.sleep(1)
Neale Ranns947ea622018-06-07 23:48:20 -0700544
545 #
546 # remove state, expect the report for the removal
547 # the dump should be empty
548 #
549 self.vapi.sw_interface_set_mtu(self.pg0.sw_if_index, [600, 0, 0, 0])
550 self.remove_group(h8)
551 self.remove_group(h9)
552 self.remove_group(h2)
553 self.remove_group(h3)
554 self.remove_group(h4)
555 self.remove_group(h5)
556 self.remove_group(h6)
557 self.remove_group(h7)
558 self.remove_group(h10)
559
560 self.logger.info(self.vapi.cli("sh igmp config"))
561 self.assertFalse(self.vapi.igmp_dump())
562
563 #
564 # TODO
565 # ADD STATE ON MORE INTERFACES
566 #
567
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200568 self.vapi.igmp_enable_disable(self.pg0.sw_if_index, 0, IGMP_MODE.HOST)
Neale Ranns947ea622018-06-07 23:48:20 -0700569
570 def test_igmp_router(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200571 """IGMP Router Functions"""
Neale Ranns947ea622018-06-07 23:48:20 -0700572
573 #
574 # Drop reports when not enabled
575 #
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200576 p_j = (
577 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
578 / IP(
579 src=self.pg0.remote_ip4,
580 dst="224.0.0.22",
581 tos=0xC0,
582 ttl=1,
583 options=[
584 IPOption(copy_flag=1, optclass="control", option="router_alert")
585 ],
586 )
587 / IGMPv3(type="Version 3 Membership Report")
588 / IGMPv3mr(numgrp=1)
589 / IGMPv3gr(
590 rtype="Allow New Sources",
591 maddr="239.1.1.1",
592 srcaddrs=["10.1.1.1", "10.1.1.2"],
593 )
594 )
595 p_l = (
596 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
597 / IP(
598 src=self.pg0.remote_ip4,
599 dst="224.0.0.22",
600 tos=0xC0,
601 options=[
602 IPOption(copy_flag=1, optclass="control", option="router_alert")
603 ],
604 )
605 / IGMPv3(type="Version 3 Membership Report")
606 / IGMPv3mr(numgrp=1)
607 / IGMPv3gr(
608 rtype="Block Old Sources",
609 maddr="239.1.1.1",
610 srcaddrs=["10.1.1.1", "10.1.1.2"],
611 )
612 )
Neale Ranns947ea622018-06-07 23:48:20 -0700613
614 self.send(self.pg0, p_j)
615 self.assertFalse(self.vapi.igmp_dump())
616
617 #
618 # drop the default timer values so these tests execute in a
619 # reasonable time frame
620 #
621 self.vapi.cli("test igmp timers query 1 src 3 leave 1")
622
623 #
624 # enable router functions on the interface
625 #
626 self.pg_enable_capture(self.pg_interfaces)
627 self.pg_start()
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200628 self.vapi.igmp_enable_disable(self.pg0.sw_if_index, 1, IGMP_MODE.ROUTER)
Neale Ranns947ea622018-06-07 23:48:20 -0700629 self.vapi.want_igmp_events(1)
630
631 #
632 # wait for router to send general query
633 #
634 for ii in range(3):
635 capture = self.pg0.get_capture(1, timeout=2)
636 self.verify_general_query(capture[0])
637 self.pg_enable_capture(self.pg_interfaces)
638 self.pg_start()
639
640 #
641 # re-send the report. VPP should now hold state for the new group
642 # VPP sends a notification that a new group has been joined
643 #
644 self.send(self.pg0, p_j)
645
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200646 self.assertTrue(
647 wait_for_igmp_event(self, 1, self.pg0, "239.1.1.1", "10.1.1.1", 1)
648 )
649 self.assertTrue(
650 wait_for_igmp_event(self, 1, self.pg0, "239.1.1.1", "10.1.1.2", 1)
651 )
Neale Ranns947ea622018-06-07 23:48:20 -0700652 dump = self.vapi.igmp_dump(self.pg0.sw_if_index)
653 self.assertEqual(len(dump), 2)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200654 self.assertTrue(find_igmp_state(dump, self.pg0, "239.1.1.1", "10.1.1.1"))
655 self.assertTrue(find_igmp_state(dump, self.pg0, "239.1.1.1", "10.1.1.2"))
Neale Ranns947ea622018-06-07 23:48:20 -0700656
657 #
658 # wait for the per-source timer to expire
659 # the state should be reaped
660 # VPP sends a notification that the group has been left
661 #
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200662 self.assertTrue(
663 wait_for_igmp_event(self, 4, self.pg0, "239.1.1.1", "10.1.1.1", 0)
664 )
665 self.assertTrue(
666 wait_for_igmp_event(self, 1, self.pg0, "239.1.1.1", "10.1.1.2", 0)
667 )
Neale Ranns947ea622018-06-07 23:48:20 -0700668 self.assertFalse(self.vapi.igmp_dump())
669
670 #
671 # resend the join. wait for two queries and then send a current-state
Paul Vinciguerra8feeaff2019-03-27 11:25:48 -0700672 # record to include all sources. this should reset the expiry time
Neale Ranns947ea622018-06-07 23:48:20 -0700673 # on the sources and thus they will still be present in 2 seconds time.
674 # If the source timer was not refreshed, then the state would have
675 # expired in 3 seconds.
676 #
677 self.send(self.pg0, p_j)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200678 self.assertTrue(
679 wait_for_igmp_event(self, 1, self.pg0, "239.1.1.1", "10.1.1.1", 1)
680 )
681 self.assertTrue(
682 wait_for_igmp_event(self, 1, self.pg0, "239.1.1.1", "10.1.1.2", 1)
683 )
Neale Ranns947ea622018-06-07 23:48:20 -0700684 dump = self.vapi.igmp_dump(self.pg0.sw_if_index)
685 self.assertEqual(len(dump), 2)
686
687 capture = self.pg0.get_capture(2, timeout=3)
688 self.verify_general_query(capture[0])
689 self.verify_general_query(capture[1])
690
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200691 p_cs = (
692 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
693 / IP(
694 src=self.pg0.remote_ip4,
695 dst="224.0.0.22",
696 tos=0xC0,
697 options=[
698 IPOption(copy_flag=1, optclass="control", option="router_alert")
699 ],
700 )
701 / IGMPv3(type="Version 3 Membership Report")
702 / IGMPv3mr(numgrp=1)
703 / IGMPv3gr(
704 rtype="Mode Is Include",
705 maddr="239.1.1.1",
706 srcaddrs=["10.1.1.1", "10.1.1.2"],
707 )
708 )
Neale Ranns947ea622018-06-07 23:48:20 -0700709
710 self.send(self.pg0, p_cs)
711
712 self.sleep(2)
713 dump = self.vapi.igmp_dump(self.pg0.sw_if_index)
714 self.assertEqual(len(dump), 2)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200715 self.assertTrue(find_igmp_state(dump, self.pg0, "239.1.1.1", "10.1.1.1"))
716 self.assertTrue(find_igmp_state(dump, self.pg0, "239.1.1.1", "10.1.1.2"))
Neale Ranns947ea622018-06-07 23:48:20 -0700717
718 #
719 # wait for the per-source timer to expire
720 # the state should be reaped
721 #
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200722 self.assertTrue(
723 wait_for_igmp_event(self, 4, self.pg0, "239.1.1.1", "10.1.1.1", 0)
724 )
725 self.assertTrue(
726 wait_for_igmp_event(self, 1, self.pg0, "239.1.1.1", "10.1.1.2", 0)
727 )
Neale Ranns947ea622018-06-07 23:48:20 -0700728 self.assertFalse(self.vapi.igmp_dump())
729
730 #
Paul Vinciguerra8feeaff2019-03-27 11:25:48 -0700731 # resend the join, then a leave. Router sends a group+source
Neale Ranns947ea622018-06-07 23:48:20 -0700732 # specific query containing both sources
733 #
734 self.send(self.pg0, p_j)
735
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200736 self.assertTrue(
737 wait_for_igmp_event(self, 1, self.pg0, "239.1.1.1", "10.1.1.1", 1)
738 )
739 self.assertTrue(
740 wait_for_igmp_event(self, 1, self.pg0, "239.1.1.1", "10.1.1.2", 1)
741 )
Neale Ranns947ea622018-06-07 23:48:20 -0700742 dump = self.vapi.igmp_dump(self.pg0.sw_if_index)
743 self.assertEqual(len(dump), 2)
744
745 self.send(self.pg0, p_l)
746 capture = self.pg0.get_capture(1, timeout=3)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200747 self.verify_group_query(capture[0], "239.1.1.1", ["10.1.1.1", "10.1.1.2"])
Neale Ranns947ea622018-06-07 23:48:20 -0700748
749 #
750 # the group specific query drops the timeout to leave (=1) seconds
751 #
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200752 self.assertTrue(
753 wait_for_igmp_event(self, 2, self.pg0, "239.1.1.1", "10.1.1.1", 0)
754 )
755 self.assertTrue(
756 wait_for_igmp_event(self, 1, self.pg0, "239.1.1.1", "10.1.1.2", 0)
757 )
Neale Ranns947ea622018-06-07 23:48:20 -0700758 self.assertFalse(self.vapi.igmp_dump())
759 self.assertFalse(self.vapi.igmp_dump())
760
761 #
Neale Ranns0f7af532018-11-06 05:51:58 -0800762 # a TO_EX({}) / IN_EX({}) is treated like a (*,G) join
Neale Rannsc17776e2018-09-26 06:51:39 -0700763 #
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200764 p_j = (
765 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
766 / IP(
767 src=self.pg0.remote_ip4,
768 dst="224.0.0.22",
769 tos=0xC0,
770 ttl=1,
771 options=[
772 IPOption(copy_flag=1, optclass="control", option="router_alert")
773 ],
774 )
775 / IGMPv3(type="Version 3 Membership Report")
776 / IGMPv3mr(numgrp=1)
777 / IGMPv3gr(rtype="Change To Exclude Mode", maddr="239.1.1.2")
778 )
Neale Rannsc17776e2018-09-26 06:51:39 -0700779
780 self.send(self.pg0, p_j)
781
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200782 self.assertTrue(
783 wait_for_igmp_event(self, 1, self.pg0, "239.1.1.2", "0.0.0.0", 1)
784 )
Neale Rannsc17776e2018-09-26 06:51:39 -0700785
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200786 p_j = (
787 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
788 / IP(
789 src=self.pg0.remote_ip4,
790 dst="224.0.0.22",
791 tos=0xC0,
792 ttl=1,
793 options=[
794 IPOption(copy_flag=1, optclass="control", option="router_alert")
795 ],
796 )
797 / IGMPv3(type="Version 3 Membership Report")
798 / IGMPv3mr(numgrp=1)
799 / IGMPv3gr(rtype="Mode Is Exclude", maddr="239.1.1.3")
800 )
Neale Ranns0f7af532018-11-06 05:51:58 -0800801
802 self.send(self.pg0, p_j)
803
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200804 self.assertTrue(
805 wait_for_igmp_event(self, 1, self.pg0, "239.1.1.3", "0.0.0.0", 1)
806 )
Neale Ranns0f7af532018-11-06 05:51:58 -0800807
808 #
Paul Vinciguerra8feeaff2019-03-27 11:25:48 -0700809 # A 'allow sources' for {} should be ignored as it should
Neale Ranns0f7af532018-11-06 05:51:58 -0800810 # never be sent.
811 #
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200812 p_j = (
813 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
814 / IP(
815 src=self.pg0.remote_ip4,
816 dst="224.0.0.22",
817 tos=0xC0,
818 ttl=1,
819 options=[
820 IPOption(copy_flag=1, optclass="control", option="router_alert")
821 ],
822 )
823 / IGMPv3(type="Version 3 Membership Report")
824 / IGMPv3mr(numgrp=1)
825 / IGMPv3gr(rtype="Allow New Sources", maddr="239.1.1.4")
826 )
Neale Ranns0f7af532018-11-06 05:51:58 -0800827
828 self.send(self.pg0, p_j)
829
830 dump = self.vapi.igmp_dump(self.pg0.sw_if_index)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200831 self.assertTrue(find_igmp_state(dump, self.pg0, "239.1.1.2", "0.0.0.0"))
832 self.assertTrue(find_igmp_state(dump, self.pg0, "239.1.1.3", "0.0.0.0"))
833 self.assertFalse(find_igmp_state(dump, self.pg0, "239.1.1.4", "0.0.0.0"))
Neale Ranns0f7af532018-11-06 05:51:58 -0800834
835 #
836 # a TO_IN({}) and IS_IN({}) are treated like a (*,G) leave
837 #
838 self.vapi.cli("set logging class igmp level debug")
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200839 p_l = (
840 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
841 / IP(
842 src=self.pg0.remote_ip4,
843 dst="224.0.0.22",
844 tos=0xC0,
845 ttl=1,
846 options=[
847 IPOption(copy_flag=1, optclass="control", option="router_alert")
848 ],
849 )
850 / IGMPv3(type="Version 3 Membership Report")
851 / IGMPv3mr(numgrp=1)
852 / IGMPv3gr(rtype="Change To Include Mode", maddr="239.1.1.2")
853 )
Neale Ranns0f7af532018-11-06 05:51:58 -0800854
855 self.send(self.pg0, p_l)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200856 self.assertTrue(
857 wait_for_igmp_event(self, 2, self.pg0, "239.1.1.2", "0.0.0.0", 0)
858 )
Neale Ranns0f7af532018-11-06 05:51:58 -0800859
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200860 p_l = (
861 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
862 / IP(
863 src=self.pg0.remote_ip4,
864 dst="224.0.0.22",
865 tos=0xC0,
866 ttl=1,
867 options=[
868 IPOption(copy_flag=1, optclass="control", option="router_alert")
869 ],
870 )
871 / IGMPv3(type="Version 3 Membership Report")
872 / IGMPv3mr(numgrp=1)
873 / IGMPv3gr(rtype="Mode Is Include", maddr="239.1.1.3")
874 )
Neale Ranns0f7af532018-11-06 05:51:58 -0800875
876 self.send(self.pg0, p_l)
877
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200878 self.assertTrue(
879 wait_for_igmp_event(self, 2, self.pg0, "239.1.1.3", "0.0.0.0", 0)
880 )
Neale Ranns0f7af532018-11-06 05:51:58 -0800881 self.assertFalse(self.vapi.igmp_dump(self.pg0.sw_if_index))
882
Neale Rannsc17776e2018-09-26 06:51:39 -0700883 #
Neale Ranns947ea622018-06-07 23:48:20 -0700884 # disable router config
885 #
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200886 self.vapi.igmp_enable_disable(self.pg0.sw_if_index, 0, IGMP_MODE.ROUTER)
Neale Ranns947ea622018-06-07 23:48:20 -0700887
Jakub Grajciar97748ca2018-10-04 11:05:35 +0200888 def _create_igmpv3_pck(self, itf, rtype, maddr, srcaddrs):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200889 p = (
890 Ether(dst=itf.local_mac, src=itf.remote_mac)
891 / IP(
892 src=itf.remote_ip4,
893 dst="224.0.0.22",
894 tos=0xC0,
895 ttl=1,
896 options=[
897 IPOption(copy_flag=1, optclass="control", option="router_alert")
898 ],
899 )
900 / IGMPv3(type="Version 3 Membership Report")
901 / IGMPv3mr(numgrp=1)
902 / IGMPv3gr(rtype=rtype, maddr=maddr, srcaddrs=srcaddrs)
903 )
Jakub Grajciar97748ca2018-10-04 11:05:35 +0200904 return p
905
906 def test_igmp_proxy_device(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200907 """IGMP proxy device"""
Jakub Grajciar97748ca2018-10-04 11:05:35 +0200908 self.pg2.admin_down()
909 self.pg2.unconfig_ip4()
910 self.pg2.set_table_ip4(0)
911 self.pg2.config_ip4()
912 self.pg2.admin_up()
913
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200914 self.vapi.cli("test igmp timers query 10 src 3 leave 1")
Jakub Grajciar97748ca2018-10-04 11:05:35 +0200915
916 # enable IGMP
917 self.vapi.igmp_enable_disable(self.pg0.sw_if_index, 1, IGMP_MODE.HOST)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200918 self.vapi.igmp_enable_disable(self.pg1.sw_if_index, 1, IGMP_MODE.ROUTER)
919 self.vapi.igmp_enable_disable(self.pg2.sw_if_index, 1, IGMP_MODE.ROUTER)
Jakub Grajciar97748ca2018-10-04 11:05:35 +0200920
921 # create IGMP proxy device
922 self.vapi.igmp_proxy_device_add_del(0, self.pg0.sw_if_index, 1)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200923 self.vapi.igmp_proxy_device_add_del_interface(0, self.pg1.sw_if_index, 1)
924 self.vapi.igmp_proxy_device_add_del_interface(0, self.pg2.sw_if_index, 1)
Jakub Grajciar97748ca2018-10-04 11:05:35 +0200925
926 # send join on pg1. join should be proxied by pg0
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200927 p_j = self._create_igmpv3_pck(
928 self.pg1, "Allow New Sources", "239.1.1.1", ["10.1.1.1", "10.1.1.2"]
929 )
Jakub Grajciar97748ca2018-10-04 11:05:35 +0200930 self.send(self.pg1, p_j)
931
932 capture = self.pg0.get_capture(1, timeout=1)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200933 self.verify_report(
934 capture[0],
935 [
936 IgmpRecord(
937 IgmpSG("239.1.1.1", ["10.1.1.1", "10.1.1.2"]), "Allow New Sources"
938 )
939 ],
940 )
Jakub Grajciar97748ca2018-10-04 11:05:35 +0200941 self.assertTrue(find_mroute(self, "239.1.1.1", "0.0.0.0", 32))
942
943 # send join on pg2. join should be proxied by pg0.
944 # the group should contain only 10.1.1.3 as
945 # 10.1.1.1 was already reported
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200946 p_j = self._create_igmpv3_pck(
947 self.pg2, "Allow New Sources", "239.1.1.1", ["10.1.1.1", "10.1.1.3"]
948 )
Jakub Grajciar97748ca2018-10-04 11:05:35 +0200949 self.send(self.pg2, p_j)
950
951 capture = self.pg0.get_capture(1, timeout=1)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200952 self.verify_report(
953 capture[0],
954 [IgmpRecord(IgmpSG("239.1.1.1", ["10.1.1.3"]), "Allow New Sources")],
955 )
Jakub Grajciar97748ca2018-10-04 11:05:35 +0200956 self.assertTrue(find_mroute(self, "239.1.1.1", "0.0.0.0", 32))
957
958 # send leave on pg2. leave for 10.1.1.3 should be proxyed
959 # as pg2 was the only interface interested in 10.1.1.3
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200960 p_l = self._create_igmpv3_pck(
961 self.pg2, "Block Old Sources", "239.1.1.1", ["10.1.1.3"]
962 )
Jakub Grajciar97748ca2018-10-04 11:05:35 +0200963 self.send(self.pg2, p_l)
964
965 capture = self.pg0.get_capture(1, timeout=2)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200966 self.verify_report(
967 capture[0],
968 [IgmpRecord(IgmpSG("239.1.1.1", ["10.1.1.3"]), "Block Old Sources")],
969 )
Jakub Grajciar97748ca2018-10-04 11:05:35 +0200970 self.assertTrue(find_mroute(self, "239.1.1.1", "0.0.0.0", 32))
971
972 # disable igmp on pg1 (also removes interface from proxy device)
973 # proxy leave for 10.1.1.2. pg2 is still interested in 10.1.1.1
974 self.pg_enable_capture(self.pg_interfaces)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200975 self.vapi.igmp_enable_disable(self.pg1.sw_if_index, 0, IGMP_MODE.ROUTER)
Jakub Grajciar97748ca2018-10-04 11:05:35 +0200976
977 capture = self.pg0.get_capture(1, timeout=1)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200978 self.verify_report(
979 capture[0],
980 [IgmpRecord(IgmpSG("239.1.1.1", ["10.1.1.2"]), "Block Old Sources")],
981 )
Jakub Grajciar97748ca2018-10-04 11:05:35 +0200982 self.assertTrue(find_mroute(self, "239.1.1.1", "0.0.0.0", 32))
983
984 # disable IGMP on pg0 and pg1.
985 # disabling IGMP on pg0 (proxy device upstream interface)
986 # removes this proxy device
987 self.vapi.igmp_enable_disable(self.pg0.sw_if_index, 0, IGMP_MODE.HOST)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200988 self.vapi.igmp_enable_disable(self.pg2.sw_if_index, 0, IGMP_MODE.ROUTER)
Jakub Grajciar97748ca2018-10-04 11:05:35 +0200989 self.assertFalse(find_mroute(self, "239.1.1.1", "0.0.0.0", 32))
990
Jakub Grajciar7b867a82017-12-08 16:28:42 +0100991
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200992if __name__ == "__main__":
Jakub Grajciar7b867a82017-12-08 16:28:42 +0100993 unittest.main(testRunner=VppTestRunner)