diff options
author | Neale Ranns <nranns@cisco.com> | 2018-11-06 05:51:58 -0800 |
---|---|---|
committer | Damjan Marion <dmarion@me.com> | 2018-11-06 17:43:26 +0000 |
commit | 0f7af53e73c47a96cc0546671a0d0a5fb5f4366c (patch) | |
tree | 0e4393cf67c2dc5ceb90b154255d2f8a0763d05e | |
parent | 3206bb15aa65f6b4bd933844cffc26967aab6ed6 (diff) |
IGMP: Improved handling of (*,G) join and leave
Change-Id: I48a92035b58d83420eb3eed3f05a75ba283543c2
Signed-off-by: Neale Ranns <nranns@cisco.com>
-rw-r--r-- | src/plugins/igmp/igmp_report.c | 94 | ||||
-rw-r--r-- | test/test_igmp.py | 69 |
2 files changed, 141 insertions, 22 deletions
diff --git a/src/plugins/igmp/igmp_report.c b/src/plugins/igmp/igmp_report.c index 7c08f342199..2e73ee15375 100644 --- a/src/plugins/igmp/igmp_report.c +++ b/src/plugins/igmp/igmp_report.c @@ -53,35 +53,48 @@ igmp_group_mk_source_list (const igmp_membership_group_v3_t * r) } static void -igmp_handle_group_update (igmp_config_t * config, - const igmp_membership_group_v3_t * igmp_group) +igmp_handle_group_exclude (igmp_config_t * config, + const igmp_membership_group_v3_t * igmp_group) { - ip46_address_t *src, *srcs; - igmp_group_t *group; ip46_address_t key = { .ip4 = igmp_group->group_address, }; + u16 n; - srcs = igmp_group_mk_source_list (igmp_group); - group = igmp_group_lookup (config, &key); - - IGMP_DBG (" ..group-update: %U (%U, %U)", - format_vnet_sw_if_index_name, - vnet_get_main (), config->sw_if_index, - format_igmp_key, &key, format_igmp_src_addr_list, srcs); + /* + * treat an exclude all sources as a *,G join + */ + n = clib_net_to_host_u16 (igmp_group->n_src_addresses); - if (NULL == group) + if (0 == n) { - group = igmp_group_alloc (config, &key, IGMP_FILTER_MODE_INCLUDE); - } + ip46_address_t *src, *srcs; + igmp_group_t *group; - /* create or update all sources */ - vec_foreach (src, srcs) - { - igmp_group_src_update (group, src, IGMP_MODE_ROUTER); - } + group = igmp_group_lookup (config, &key); + srcs = igmp_group_mk_source_list (igmp_group); - vec_free (srcs); + IGMP_DBG (" ..group-update: %U (*, %U)", + format_vnet_sw_if_index_name, + vnet_get_main (), config->sw_if_index, format_igmp_key, &key); + + if (NULL == group) + { + group = igmp_group_alloc (config, &key, IGMP_FILTER_MODE_INCLUDE); + } + vec_foreach (src, srcs) + { + igmp_group_src_update (group, src, IGMP_MODE_ROUTER); + } + + vec_free (srcs); + } + else + { + IGMP_DBG (" ..group-update: %U (*, %U) source exclude ignored", + format_vnet_sw_if_index_name, + vnet_get_main (), config->sw_if_index, format_igmp_key, &key); + } } static void @@ -132,6 +145,46 @@ igmp_handle_group_block (igmp_config_t * config, } static void +igmp_handle_group_update (igmp_config_t * config, + const igmp_membership_group_v3_t * igmp_group) +{ + ip46_address_t *src, *srcs; + igmp_group_t *group; + ip46_address_t key = { + .ip4 = igmp_group->group_address, + }; + + /* + * treat a TO_INC({}) as a (*,G) leave + */ + if (0 == clib_net_to_host_u16 (igmp_group->n_src_addresses)) + { + return (igmp_handle_group_block (config, igmp_group)); + } + + srcs = igmp_group_mk_source_list (igmp_group); + group = igmp_group_lookup (config, &key); + + IGMP_DBG (" ..group-update: %U (%U, %U)", + format_vnet_sw_if_index_name, + vnet_get_main (), config->sw_if_index, + format_igmp_key, &key, format_igmp_src_addr_list, srcs); + + if (NULL == group) + { + group = igmp_group_alloc (config, &key, IGMP_FILTER_MODE_INCLUDE); + } + + /* create or update all sources */ + vec_foreach (src, srcs) + { + igmp_group_src_update (group, src, IGMP_MODE_ROUTER); + } + + vec_free (srcs); +} + +static void igmp_handle_group (igmp_config_t * config, const igmp_membership_group_v3_t * igmp_group) { @@ -151,6 +204,7 @@ igmp_handle_group (igmp_config_t * config, break; case IGMP_MEMBERSHIP_GROUP_mode_is_exclude: case IGMP_MEMBERSHIP_GROUP_change_to_exclude: + igmp_handle_group_exclude (config, igmp_group); break; /* * all other types ignored diff --git a/test/test_igmp.py b/test/test_igmp.py index da2fa9a304e..c1452c9b83f 100644 --- a/test/test_igmp.py +++ b/test/test_igmp.py @@ -629,7 +629,7 @@ class TestIgmp(VppTestCase): self.assertFalse(self.vapi.igmp_dump()) # - # A (*,G) host report + # 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, @@ -637,13 +637,78 @@ class TestIgmp(VppTestCase): option="router_alert")]) / IGMPv3(type="Version 3 Membership Report") / IGMPv3mr(numgrp=1) / - IGMPv3gr(rtype="Allow New Sources", maddr="239.1.1.2")) + 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 sourcees' 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 # |