summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNeale Ranns <nranns@cisco.com>2018-11-06 05:51:58 -0800
committerDamjan Marion <dmarion@me.com>2018-11-06 17:43:26 +0000
commit0f7af53e73c47a96cc0546671a0d0a5fb5f4366c (patch)
tree0e4393cf67c2dc5ceb90b154255d2f8a0763d05e
parent3206bb15aa65f6b4bd933844cffc26967aab6ed6 (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.c94
-rw-r--r--test/test_igmp.py69
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
#