X-Git-Url: https://gerrit.fd.io/r/gitweb?a=blobdiff_plain;f=test%2Ftest_igmp.py;fp=test%2Ftest_igmp.py;h=0000000000000000000000000000000000000000;hb=a43c93f8554ad7418e31be3791b3fb71232f60ac;hp=f1c49acba4c54183c2ae5ab51dedd65bf16b5076;hpb=34af0ccf5cf27d8a72119626d2d009222e4ff0a6;p=vpp.git diff --git a/test/test_igmp.py b/test/test_igmp.py deleted file mode 100644 index f1c49acba4c..00000000000 --- a/test/test_igmp.py +++ /dev/null @@ -1,834 +0,0 @@ -#!/usr/bin/env python - -import unittest - -from scapy.layers.l2 import Ether, Raw -from scapy.layers.inet import IP, IPOption -from scapy.contrib.igmpv3 import IGMPv3, IGMPv3gr, IGMPv3mq, IGMPv3mr - -from framework import VppTestCase, VppTestRunner, running_extended_tests -from vpp_igmp import find_igmp_state, IGMP_FILTER, IgmpRecord, IGMP_MODE, \ - IgmpSG, VppHostState, wait_for_igmp_event -from vpp_ip_route import find_mroute, VppIpTable - - -class IgmpMode: - HOST = 1 - ROUTER = 0 - - -class TestIgmp(VppTestCase): - """ IGMP Test Case """ - - @classmethod - def setUpClass(cls): - super(TestIgmp, cls).setUpClass() - - @classmethod - def tearDownClass(cls): - super(TestIgmp, cls).tearDownClass() - - def setUp(self): - super(TestIgmp, self).setUp() - - self.create_pg_interfaces(range(4)) - self.sg_list = [] - self.config_list = [] - - self.ip_addr = [] - self.ip_table = VppIpTable(self, 1) - self.ip_table.add_vpp_config() - - for pg in self.pg_interfaces[2:]: - pg.set_table_ip4(1) - for pg in self.pg_interfaces: - pg.admin_up() - pg.config_ip4() - pg.resolve_arp() - - def tearDown(self): - for pg in self.pg_interfaces: - self.vapi.igmp_clear_interface(pg.sw_if_index) - pg.unconfig_ip4() - pg.set_table_ip4(0) - pg.admin_down() - super(TestIgmp, self).tearDown() - - def send(self, ti, pkts): - ti.add_stream(pkts) - self.pg_enable_capture(self.pg_interfaces) - self.pg_start() - - def test_igmp_flush(self): - """ IGMP Link Up/down and Flush """ - - # - # FIX THIS. Link down. - # - - def test_igmp_enable(self): - """ IGMP enable/disable on an interface - - check for the addition/removal of the IGMP mroutes """ - - self.vapi.igmp_enable_disable(self.pg0.sw_if_index, 1, IGMP_MODE.HOST) - self.vapi.igmp_enable_disable(self.pg1.sw_if_index, 1, IGMP_MODE.HOST) - - self.assertTrue(find_mroute(self, "224.0.0.1", "0.0.0.0", 32)) - self.assertTrue(find_mroute(self, "224.0.0.22", "0.0.0.0", 32)) - - self.vapi.igmp_enable_disable(self.pg2.sw_if_index, 1, IGMP_MODE.HOST) - self.vapi.igmp_enable_disable(self.pg3.sw_if_index, 1, IGMP_MODE.HOST) - - self.assertTrue(find_mroute(self, "224.0.0.1", "0.0.0.0", 32, - table_id=1)) - self.assertTrue(find_mroute(self, "224.0.0.22", "0.0.0.0", 32, - table_id=1)) - self.vapi.igmp_enable_disable(self.pg0.sw_if_index, 0, IGMP_MODE.HOST) - self.vapi.igmp_enable_disable(self.pg1.sw_if_index, 0, IGMP_MODE.HOST) - self.vapi.igmp_enable_disable(self.pg2.sw_if_index, 0, IGMP_MODE.HOST) - self.vapi.igmp_enable_disable(self.pg3.sw_if_index, 0, IGMP_MODE.HOST) - - self.assertFalse(find_mroute(self, "224.0.0.1", "0.0.0.0", 32)) - self.assertFalse(find_mroute(self, "224.0.0.22", "0.0.0.0", 32)) - self.assertFalse(find_mroute(self, "224.0.0.1", "0.0.0.0", 32, - table_id=1)) - self.assertFalse(find_mroute(self, "224.0.0.22", "0.0.0.0", 32, - table_id=1)) - - def verify_general_query(self, p): - ip = p[IP] - self.assertEqual(len(ip.options), 1) - self.assertEqual(ip.options[0].option, 20) - self.assertEqual(ip.dst, "224.0.0.1") - self.assertEqual(ip.proto, 2) - igmp = p[IGMPv3] - self.assertEqual(igmp.type, 0x11) - self.assertEqual(igmp.gaddr, "0.0.0.0") - - def verify_group_query(self, p, grp, srcs): - ip = p[IP] - self.assertEqual(ip.dst, grp) - self.assertEqual(ip.proto, 2) - self.assertEqual(len(ip.options), 1) - self.assertEqual(ip.options[0].option, 20) - self.assertEqual(ip.proto, 2) - igmp = p[IGMPv3] - self.assertEqual(igmp.type, 0x11) - self.assertEqual(igmp.gaddr, grp) - - def verify_report(self, rx, records): - ip = rx[IP] - self.assertEqual(rx[IP].dst, "224.0.0.22") - self.assertEqual(len(ip.options), 1) - self.assertEqual(ip.options[0].option, 20) - self.assertEqual(ip.proto, 2) - self.assertEqual(IGMPv3.igmpv3types[rx[IGMPv3].type], - "Version 3 Membership Report") - self.assertEqual(rx[IGMPv3mr].numgrp, len(records)) - - received = rx[IGMPv3mr].records - - for ii in range(len(records)): - gr = received[ii] - r = records[ii] - self.assertEqual(IGMPv3gr.igmpv3grtypes[gr.rtype], r.type) - self.assertEqual(gr.numsrc, len(r.sg.saddrs)) - self.assertEqual(gr.maddr, r.sg.gaddr) - self.assertEqual(len(gr.srcaddrs), len(r.sg.saddrs)) - - self.assertEqual(sorted(gr.srcaddrs), - sorted(r.sg.saddrs)) - - def add_group(self, itf, sg, n_pkts=2): - self.pg_enable_capture(self.pg_interfaces) - self.pg_start() - - hs = VppHostState(self, - IGMP_FILTER.INCLUDE, - itf.sw_if_index, - sg) - hs.add_vpp_config() - - capture = itf.get_capture(n_pkts, timeout=10) - - # reports are transmitted twice due to default rebostness value=2 - self.verify_report(capture[0], - [IgmpRecord(sg, "Allow New Sources")]), - self.verify_report(capture[1], - [IgmpRecord(sg, "Allow New Sources")]), - - return hs - - def remove_group(self, hs): - self.pg_enable_capture(self.pg_interfaces) - self.pg_start() - hs.remove_vpp_config() - - capture = self.pg0.get_capture(1, timeout=10) - - self.verify_report(capture[0], - [IgmpRecord(hs.sg, "Block Old Sources")]) - - def test_igmp_host(self): - """ IGMP Host functions """ - - # - # Enable interface for host functions - # - self.vapi.igmp_enable_disable(self.pg0.sw_if_index, - 1, - IGMP_MODE.HOST) - - # - # Add one S,G of state and expect a state-change event report - # indicating the addition of the S,G - # - h1 = self.add_group(self.pg0, IgmpSG("239.1.1.1", ["1.1.1.1"])) - - # search for the corresponding state created in VPP - dump = self.vapi.igmp_dump(self.pg0.sw_if_index) - self.assertEqual(len(dump), 1) - self.assertTrue(find_igmp_state(dump, self.pg0, - "239.1.1.1", "1.1.1.1")) - - # - # Send a general query (to the all router's address) - # expect VPP to respond with a membership report. - # Pad the query with 0 - some devices in the big wild - # internet are prone to this. - # - p_g = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) / - IP(src=self.pg0.remote_ip4, dst='224.0.0.1', tos=0xc0) / - IGMPv3(type="Membership Query", mrcode=100) / - IGMPv3mq(gaddr="0.0.0.0") / - Raw('\x00' * 10)) - - self.send(self.pg0, p_g) - - capture = self.pg0.get_capture(1, timeout=10) - self.verify_report(capture[0], - [IgmpRecord(h1.sg, "Mode Is Include")]) - - # - # Group specific query - # - p_gs = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) / - IP(src=self.pg0.remote_ip4, dst='239.1.1.1', tos=0xc0, - options=[IPOption(copy_flag=1, optclass="control", - option="router_alert")]) / - IGMPv3(type="Membership Query", mrcode=100) / - IGMPv3mq(gaddr="239.1.1.1")) - - self.send(self.pg0, p_gs) - - capture = self.pg0.get_capture(1, timeout=10) - self.verify_report(capture[0], - [IgmpRecord(h1.sg, "Mode Is Include")]) - - # - # A group and source specific query, with the source matching - # the source VPP has - # - p_gs1 = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) / - IP(src=self.pg0.remote_ip4, dst='239.1.1.1', tos=0xc0, - options=[IPOption(copy_flag=1, optclass="control", - option="router_alert")]) / - IGMPv3(type="Membership Query", mrcode=100) / - IGMPv3mq(gaddr="239.1.1.1", srcaddrs=["1.1.1.1"])) - - self.send(self.pg0, p_gs1) - - capture = self.pg0.get_capture(1, timeout=10) - self.verify_report(capture[0], - [IgmpRecord(h1.sg, "Mode Is Include")]) - - # - # A group and source specific query that reports more sources - # than the packet actually has. - # - p_gs2 = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) / - IP(src=self.pg0.remote_ip4, dst='239.1.1.1', tos=0xc0, - options=[IPOption(copy_flag=1, optclass="control", - option="router_alert")]) / - IGMPv3(type="Membership Query", mrcode=100) / - IGMPv3mq(gaddr="239.1.1.1", numsrc=4, srcaddrs=["1.1.1.1"])) - - self.send_and_assert_no_replies(self.pg0, p_gs2, timeout=10) - - # - # A group and source specific query, with the source NOT matching - # the source VPP has. There should be no response. - # - p_gs2 = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) / - IP(src=self.pg0.remote_ip4, dst='239.1.1.1', tos=0xc0, - options=[IPOption(copy_flag=1, optclass="control", - option="router_alert")]) / - IGMPv3(type="Membership Query", mrcode=100) / - IGMPv3mq(gaddr="239.1.1.1", srcaddrs=["1.1.1.2"])) - - self.send_and_assert_no_replies(self.pg0, p_gs2, timeout=10) - - # - # A group and source specific query, with the multiple sources - # one of which matches the source VPP has. - # The report should contain only the source VPP has. - # - p_gs3 = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) / - IP(src=self.pg0.remote_ip4, dst='239.1.1.1', tos=0xc0, - options=[IPOption(copy_flag=1, optclass="control", - option="router_alert")]) / - IGMPv3(type="Membership Query", mrcode=100) / - IGMPv3mq(gaddr="239.1.1.1", - srcaddrs=["1.1.1.1", "1.1.1.2", "1.1.1.3"])) - - self.send(self.pg0, p_gs3) - - capture = self.pg0.get_capture(1, timeout=10) - self.verify_report(capture[0], - [IgmpRecord(h1.sg, "Mode Is Include")]) - - # - # Two source and group specific queries in quick succession, the - # first does not have VPPs source the second does. then vice-versa - # - self.send(self.pg0, [p_gs2, p_gs1]) - capture = self.pg0.get_capture(1, timeout=10) - self.verify_report(capture[0], - [IgmpRecord(h1.sg, "Mode Is Include")]) - - self.send(self.pg0, [p_gs1, p_gs2]) - capture = self.pg0.get_capture(1, timeout=10) - self.verify_report(capture[0], - [IgmpRecord(h1.sg, "Mode Is Include")]) - - # - # remove state, expect the report for the removal - # - self.remove_group(h1) - - dump = self.vapi.igmp_dump() - self.assertFalse(dump) - - # - # A group with multiple sources - # - h2 = self.add_group(self.pg0, - IgmpSG("239.1.1.1", - ["1.1.1.1", "1.1.1.2", "1.1.1.3"])) - - # search for the corresponding state created in VPP - dump = self.vapi.igmp_dump(self.pg0.sw_if_index) - self.assertEqual(len(dump), 3) - for s in h2.sg.saddrs: - self.assertTrue(find_igmp_state(dump, self.pg0, - "239.1.1.1", s)) - # - # Send a general query (to the all router's address) - # expect VPP to respond with a membership report will all sources - # - self.send(self.pg0, p_g) - - capture = self.pg0.get_capture(1, timeout=10) - self.verify_report(capture[0], - [IgmpRecord(h2.sg, "Mode Is Include")]) - - # - # Group and source specific query; some present some not - # - p_gs = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) / - IP(src=self.pg0.remote_ip4, dst='239.1.1.1', tos=0xc0, - options=[IPOption(copy_flag=1, optclass="control", - option="router_alert")]) / - IGMPv3(type="Membership Query", mrcode=100) / - IGMPv3mq(gaddr="239.1.1.1", - srcaddrs=["1.1.1.1", "1.1.1.2", "1.1.1.4"])) - - self.send(self.pg0, p_gs) - - capture = self.pg0.get_capture(1, timeout=10) - self.verify_report(capture[0], - [IgmpRecord( - IgmpSG('239.1.1.1', ["1.1.1.1", "1.1.1.2"]), - "Mode Is Include")]) - - # - # add loads more groups - # - h3 = self.add_group(self.pg0, - IgmpSG("239.1.1.2", - ["2.1.1.1", "2.1.1.2", "2.1.1.3"])) - h4 = self.add_group(self.pg0, - IgmpSG("239.1.1.3", - ["3.1.1.1", "3.1.1.2", "3.1.1.3"])) - h5 = self.add_group(self.pg0, - IgmpSG("239.1.1.4", - ["4.1.1.1", "4.1.1.2", "4.1.1.3"])) - h6 = self.add_group(self.pg0, - IgmpSG("239.1.1.5", - ["5.1.1.1", "5.1.1.2", "5.1.1.3"])) - h7 = self.add_group(self.pg0, - IgmpSG("239.1.1.6", - ["6.1.1.1", "6.1.1.2", - "6.1.1.3", "6.1.1.4", - "6.1.1.5", "6.1.1.6", - "6.1.1.7", "6.1.1.8", - "6.1.1.9", "6.1.1.10", - "6.1.1.11", "6.1.1.12", - "6.1.1.13", "6.1.1.14", - "6.1.1.15", "6.1.1.16"])) - - # - # general query. - # the order the groups come in is not important, so what is - # checked for is what VPP is sending today. - # - self.send(self.pg0, p_g) - - capture = self.pg0.get_capture(1, timeout=10) - - self.verify_report(capture[0], - [IgmpRecord(h3.sg, "Mode Is Include"), - IgmpRecord(h2.sg, "Mode Is Include"), - IgmpRecord(h6.sg, "Mode Is Include"), - IgmpRecord(h4.sg, "Mode Is Include"), - IgmpRecord(h5.sg, "Mode Is Include"), - IgmpRecord(h7.sg, "Mode Is Include")]) - - # - # modify a group to add and remove some sources - # - h7.sg = IgmpSG("239.1.1.6", - ["6.1.1.1", "6.1.1.2", - "6.1.1.5", "6.1.1.6", - "6.1.1.7", "6.1.1.8", - "6.1.1.9", "6.1.1.10", - "6.1.1.11", "6.1.1.12", - "6.1.1.13", "6.1.1.14", - "6.1.1.15", "6.1.1.16", - "6.1.1.17", "6.1.1.18"]) - - self.pg_enable_capture(self.pg_interfaces) - self.pg_start() - h7.add_vpp_config() - - capture = self.pg0.get_capture(1, timeout=10) - self.verify_report(capture[0], - [IgmpRecord(IgmpSG("239.1.1.6", - ["6.1.1.17", "6.1.1.18"]), - "Allow New Sources"), - IgmpRecord(IgmpSG("239.1.1.6", - ["6.1.1.3", "6.1.1.4"]), - "Block Old Sources")]) - - # - # add an additional groups with many sources so that each group - # consumes the link MTU. We should therefore see multiple state - # state reports when queried. - # - self.vapi.sw_interface_set_mtu(self.pg0.sw_if_index, [560, 0, 0, 0]) - - src_list = [] - for i in range(128): - src_list.append("10.1.1.%d" % i) - - h8 = self.add_group(self.pg0, - IgmpSG("238.1.1.1", src_list)) - h9 = self.add_group(self.pg0, - IgmpSG("238.1.1.2", src_list)) - - self.send(self.pg0, p_g) - - capture = self.pg0.get_capture(4, timeout=10) - - self.verify_report(capture[0], - [IgmpRecord(h3.sg, "Mode Is Include"), - IgmpRecord(h2.sg, "Mode Is Include"), - IgmpRecord(h6.sg, "Mode Is Include"), - IgmpRecord(h4.sg, "Mode Is Include"), - IgmpRecord(h5.sg, "Mode Is Include")]) - self.verify_report(capture[1], - [IgmpRecord(h8.sg, "Mode Is Include")]) - self.verify_report(capture[2], - [IgmpRecord(h7.sg, "Mode Is Include")]) - self.verify_report(capture[3], - [IgmpRecord(h9.sg, "Mode Is Include")]) - - # - # drop the MTU further (so a 128 sized group won't fit) - # - self.vapi.sw_interface_set_mtu(self.pg0.sw_if_index, [512, 0, 0, 0]) - - self.pg_enable_capture(self.pg_interfaces) - self.pg_start() - - h10 = VppHostState(self, - IGMP_FILTER.INCLUDE, - self.pg0.sw_if_index, - IgmpSG("238.1.1.3", src_list)) - h10.add_vpp_config() - - capture = self.pg0.get_capture(2, timeout=10) - # wait for a little bit - self.sleep(1) - - # - # remove state, expect the report for the removal - # the dump should be empty - # - self.vapi.sw_interface_set_mtu(self.pg0.sw_if_index, [600, 0, 0, 0]) - self.remove_group(h8) - self.remove_group(h9) - self.remove_group(h2) - self.remove_group(h3) - self.remove_group(h4) - self.remove_group(h5) - self.remove_group(h6) - self.remove_group(h7) - self.remove_group(h10) - - self.logger.info(self.vapi.cli("sh igmp config")) - self.assertFalse(self.vapi.igmp_dump()) - - # - # TODO - # ADD STATE ON MORE INTERFACES - # - - self.vapi.igmp_enable_disable(self.pg0.sw_if_index, - 0, - IGMP_MODE.HOST) - - def test_igmp_router(self): - """ IGMP Router Functions """ - - # - # Drop reports when not enabled - # - p_j = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) / - IP(src=self.pg0.remote_ip4, dst="224.0.0.22", tos=0xc0, ttl=1, - options=[IPOption(copy_flag=1, optclass="control", - option="router_alert")]) / - IGMPv3(type="Version 3 Membership Report") / - IGMPv3mr(numgrp=1) / - IGMPv3gr(rtype="Allow New Sources", - maddr="239.1.1.1", srcaddrs=["10.1.1.1", "10.1.1.2"])) - p_l = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) / - IP(src=self.pg0.remote_ip4, dst="224.0.0.22", tos=0xc0, - options=[IPOption(copy_flag=1, optclass="control", - option="router_alert")]) / - IGMPv3(type="Version 3 Membership Report") / - IGMPv3mr(numgrp=1) / - IGMPv3gr(rtype="Block Old Sources", - maddr="239.1.1.1", srcaddrs=["10.1.1.1", "10.1.1.2"])) - - self.send(self.pg0, p_j) - self.assertFalse(self.vapi.igmp_dump()) - - # - # drop the default timer values so these tests execute in a - # reasonable time frame - # - self.vapi.cli("test igmp timers query 1 src 3 leave 1") - - # - # enable router functions on the interface - # - self.pg_enable_capture(self.pg_interfaces) - self.pg_start() - self.vapi.igmp_enable_disable(self.pg0.sw_if_index, - 1, - IGMP_MODE.ROUTER) - self.vapi.want_igmp_events(1) - - # - # wait for router to send general query - # - for ii in range(3): - capture = self.pg0.get_capture(1, timeout=2) - self.verify_general_query(capture[0]) - self.pg_enable_capture(self.pg_interfaces) - self.pg_start() - - # - # re-send the report. VPP should now hold state for the new group - # VPP sends a notification that a new group has been joined - # - self.send(self.pg0, p_j) - - self.assertTrue(wait_for_igmp_event(self, 1, self.pg0, - "239.1.1.1", "10.1.1.1", 1)) - self.assertTrue(wait_for_igmp_event(self, 1, self.pg0, - "239.1.1.1", "10.1.1.2", 1)) - dump = self.vapi.igmp_dump(self.pg0.sw_if_index) - self.assertEqual(len(dump), 2) - self.assertTrue(find_igmp_state(dump, self.pg0, - "239.1.1.1", "10.1.1.1")) - self.assertTrue(find_igmp_state(dump, self.pg0, - "239.1.1.1", "10.1.1.2")) - - # - # wait for the per-source timer to expire - # the state should be reaped - # VPP sends a notification that the group has been left - # - self.assertTrue(wait_for_igmp_event(self, 4, self.pg0, - "239.1.1.1", "10.1.1.1", 0)) - self.assertTrue(wait_for_igmp_event(self, 1, self.pg0, - "239.1.1.1", "10.1.1.2", 0)) - self.assertFalse(self.vapi.igmp_dump()) - - # - # resend the join. wait for two queries and then send a current-state - # record to include all sources. this should reset the expiry time - # on the sources and thus they will still be present in 2 seconds time. - # If the source timer was not refreshed, then the state would have - # expired in 3 seconds. - # - self.send(self.pg0, p_j) - self.assertTrue(wait_for_igmp_event(self, 1, self.pg0, - "239.1.1.1", "10.1.1.1", 1)) - self.assertTrue(wait_for_igmp_event(self, 1, self.pg0, - "239.1.1.1", "10.1.1.2", 1)) - dump = self.vapi.igmp_dump(self.pg0.sw_if_index) - self.assertEqual(len(dump), 2) - - capture = self.pg0.get_capture(2, timeout=3) - self.verify_general_query(capture[0]) - self.verify_general_query(capture[1]) - - p_cs = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) / - IP(src=self.pg0.remote_ip4, dst="224.0.0.22", tos=0xc0, - options=[IPOption(copy_flag=1, optclass="control", - option="router_alert")]) / - IGMPv3(type="Version 3 Membership Report") / - IGMPv3mr(numgrp=1) / - IGMPv3gr(rtype="Mode Is Include", - maddr="239.1.1.1", srcaddrs=["10.1.1.1", "10.1.1.2"])) - - self.send(self.pg0, p_cs) - - self.sleep(2) - dump = self.vapi.igmp_dump(self.pg0.sw_if_index) - self.assertEqual(len(dump), 2) - self.assertTrue(find_igmp_state(dump, self.pg0, - "239.1.1.1", "10.1.1.1")) - self.assertTrue(find_igmp_state(dump, self.pg0, - "239.1.1.1", "10.1.1.2")) - - # - # wait for the per-source timer to expire - # the state should be reaped - # - self.assertTrue(wait_for_igmp_event(self, 4, self.pg0, - "239.1.1.1", "10.1.1.1", 0)) - self.assertTrue(wait_for_igmp_event(self, 1, self.pg0, - "239.1.1.1", "10.1.1.2", 0)) - self.assertFalse(self.vapi.igmp_dump()) - - # - # resend the join, then a leave. Router sends a group+source - # specific query containing both sources - # - self.send(self.pg0, p_j) - - self.assertTrue(wait_for_igmp_event(self, 1, self.pg0, - "239.1.1.1", "10.1.1.1", 1)) - self.assertTrue(wait_for_igmp_event(self, 1, self.pg0, - "239.1.1.1", "10.1.1.2", 1)) - dump = self.vapi.igmp_dump(self.pg0.sw_if_index) - self.assertEqual(len(dump), 2) - - self.send(self.pg0, p_l) - capture = self.pg0.get_capture(1, timeout=3) - self.verify_group_query(capture[0], "239.1.1.1", - ["10.1.1.1", "10.1.1.2"]) - - # - # the group specific query drops the timeout to leave (=1) seconds - # - self.assertTrue(wait_for_igmp_event(self, 2, self.pg0, - "239.1.1.1", "10.1.1.1", 0)) - self.assertTrue(wait_for_igmp_event(self, 1, self.pg0, - "239.1.1.1", "10.1.1.2", 0)) - self.assertFalse(self.vapi.igmp_dump()) - self.assertFalse(self.vapi.igmp_dump()) - - # - # a TO_EX({}) / IN_EX({}) is treated like a (*,G) join - # - p_j = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) / - IP(src=self.pg0.remote_ip4, dst="224.0.0.22", tos=0xc0, ttl=1, - options=[IPOption(copy_flag=1, optclass="control", - option="router_alert")]) / - IGMPv3(type="Version 3 Membership Report") / - IGMPv3mr(numgrp=1) / - IGMPv3gr(rtype="Change To Exclude Mode", maddr="239.1.1.2")) - - self.send(self.pg0, p_j) - - self.assertTrue(wait_for_igmp_event(self, 1, self.pg0, - "239.1.1.2", "0.0.0.0", 1)) - - p_j = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) / - IP(src=self.pg0.remote_ip4, dst="224.0.0.22", tos=0xc0, ttl=1, - options=[IPOption(copy_flag=1, optclass="control", - option="router_alert")]) / - IGMPv3(type="Version 3 Membership Report") / - IGMPv3mr(numgrp=1) / - IGMPv3gr(rtype="Mode Is Exclude", maddr="239.1.1.3")) - - self.send(self.pg0, p_j) - - self.assertTrue(wait_for_igmp_event(self, 1, self.pg0, - "239.1.1.3", "0.0.0.0", 1)) - - # - # A 'allow sources' for {} should be ignored as it should - # never be sent. - # - p_j = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) / - IP(src=self.pg0.remote_ip4, dst="224.0.0.22", tos=0xc0, ttl=1, - options=[IPOption(copy_flag=1, optclass="control", - option="router_alert")]) / - IGMPv3(type="Version 3 Membership Report") / - IGMPv3mr(numgrp=1) / - IGMPv3gr(rtype="Allow New Sources", maddr="239.1.1.4")) - - self.send(self.pg0, p_j) - - dump = self.vapi.igmp_dump(self.pg0.sw_if_index) - self.assertTrue(find_igmp_state(dump, self.pg0, - "239.1.1.2", "0.0.0.0")) - self.assertTrue(find_igmp_state(dump, self.pg0, - "239.1.1.3", "0.0.0.0")) - self.assertFalse(find_igmp_state(dump, self.pg0, - "239.1.1.4", "0.0.0.0")) - - # - # a TO_IN({}) and IS_IN({}) are treated like a (*,G) leave - # - self.vapi.cli("set logging class igmp level debug") - p_l = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) / - IP(src=self.pg0.remote_ip4, dst="224.0.0.22", tos=0xc0, ttl=1, - options=[IPOption(copy_flag=1, optclass="control", - option="router_alert")]) / - IGMPv3(type="Version 3 Membership Report") / - IGMPv3mr(numgrp=1) / - IGMPv3gr(rtype="Change To Include Mode", maddr="239.1.1.2")) - - self.send(self.pg0, p_l) - self.assertTrue(wait_for_igmp_event(self, 2, self.pg0, - "239.1.1.2", "0.0.0.0", 0)) - - p_l = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) / - IP(src=self.pg0.remote_ip4, dst="224.0.0.22", tos=0xc0, ttl=1, - options=[IPOption(copy_flag=1, optclass="control", - option="router_alert")]) / - IGMPv3(type="Version 3 Membership Report") / - IGMPv3mr(numgrp=1) / - IGMPv3gr(rtype="Mode Is Include", maddr="239.1.1.3")) - - self.send(self.pg0, p_l) - - self.assertTrue(wait_for_igmp_event(self, 2, self.pg0, - "239.1.1.3", "0.0.0.0", 0)) - self.assertFalse(self.vapi.igmp_dump(self.pg0.sw_if_index)) - - # - # disable router config - # - self.vapi.igmp_enable_disable(self.pg0.sw_if_index, - 0, - IGMP_MODE.ROUTER) - - def _create_igmpv3_pck(self, itf, rtype, maddr, srcaddrs): - p = (Ether(dst=itf.local_mac, src=itf.remote_mac) / - IP(src=itf.remote_ip4, dst="224.0.0.22", tos=0xc0, ttl=1, - options=[IPOption(copy_flag=1, optclass="control", - option="router_alert")]) / - IGMPv3(type="Version 3 Membership Report") / - IGMPv3mr(numgrp=1) / - IGMPv3gr(rtype=rtype, - maddr=maddr, srcaddrs=srcaddrs)) - return p - - def test_igmp_proxy_device(self): - """ IGMP proxy device """ - self.pg2.admin_down() - self.pg2.unconfig_ip4() - self.pg2.set_table_ip4(0) - self.pg2.config_ip4() - self.pg2.admin_up() - - self.vapi.cli('test igmp timers query 10 src 3 leave 1') - - # enable IGMP - self.vapi.igmp_enable_disable(self.pg0.sw_if_index, 1, IGMP_MODE.HOST) - self.vapi.igmp_enable_disable(self.pg1.sw_if_index, 1, - IGMP_MODE.ROUTER) - self.vapi.igmp_enable_disable(self.pg2.sw_if_index, 1, - IGMP_MODE.ROUTER) - - # create IGMP proxy device - self.vapi.igmp_proxy_device_add_del(0, self.pg0.sw_if_index, 1) - self.vapi.igmp_proxy_device_add_del_interface(0, - self.pg1.sw_if_index, 1) - self.vapi.igmp_proxy_device_add_del_interface(0, - self.pg2.sw_if_index, 1) - - # send join on pg1. join should be proxied by pg0 - p_j = self._create_igmpv3_pck(self.pg1, "Allow New Sources", - "239.1.1.1", ["10.1.1.1", "10.1.1.2"]) - self.send(self.pg1, p_j) - - capture = self.pg0.get_capture(1, timeout=1) - self.verify_report(capture[0], [IgmpRecord(IgmpSG("239.1.1.1", - ["10.1.1.1", "10.1.1.2"]), "Allow New Sources")]) - self.assertTrue(find_mroute(self, "239.1.1.1", "0.0.0.0", 32)) - - # send join on pg2. join should be proxied by pg0. - # the group should contain only 10.1.1.3 as - # 10.1.1.1 was already reported - p_j = self._create_igmpv3_pck(self.pg2, "Allow New Sources", - "239.1.1.1", ["10.1.1.1", "10.1.1.3"]) - self.send(self.pg2, p_j) - - capture = self.pg0.get_capture(1, timeout=1) - self.verify_report(capture[0], [IgmpRecord(IgmpSG("239.1.1.1", - ["10.1.1.3"]), "Allow New Sources")]) - self.assertTrue(find_mroute(self, "239.1.1.1", "0.0.0.0", 32)) - - # send leave on pg2. leave for 10.1.1.3 should be proxyed - # as pg2 was the only interface interested in 10.1.1.3 - p_l = self._create_igmpv3_pck(self.pg2, "Block Old Sources", - "239.1.1.1", ["10.1.1.3"]) - self.send(self.pg2, p_l) - - capture = self.pg0.get_capture(1, timeout=2) - self.verify_report(capture[0], [IgmpRecord(IgmpSG("239.1.1.1", - ["10.1.1.3"]), "Block Old Sources")]) - self.assertTrue(find_mroute(self, "239.1.1.1", "0.0.0.0", 32)) - - # disable igmp on pg1 (also removes interface from proxy device) - # proxy leave for 10.1.1.2. pg2 is still interested in 10.1.1.1 - self.pg_enable_capture(self.pg_interfaces) - self.vapi.igmp_enable_disable(self.pg1.sw_if_index, 0, - IGMP_MODE.ROUTER) - - capture = self.pg0.get_capture(1, timeout=1) - self.verify_report(capture[0], [IgmpRecord(IgmpSG("239.1.1.1", - ["10.1.1.2"]), "Block Old Sources")]) - self.assertTrue(find_mroute(self, "239.1.1.1", "0.0.0.0", 32)) - - # disable IGMP on pg0 and pg1. - # disabling IGMP on pg0 (proxy device upstream interface) - # removes this proxy device - self.vapi.igmp_enable_disable(self.pg0.sw_if_index, 0, IGMP_MODE.HOST) - self.vapi.igmp_enable_disable(self.pg2.sw_if_index, 0, - IGMP_MODE.ROUTER) - self.assertFalse(find_mroute(self, "239.1.1.1", "0.0.0.0", 32)) - - -if __name__ == '__main__': - unittest.main(testRunner=VppTestRunner)