summaryrefslogtreecommitdiff
path: root/cleopatre/application
diff options
context:
space:
mode:
authorYacine Belkadi2011-03-28 13:25:47 +0200
committerYacine Belkadi2011-04-08 16:46:15 +0200
commitc18c1e7794f5ba28f7a71c93628777d754d6145f (patch)
treeef1331dd2f5d2c85604bfc3851b3e0955fdcdb2e /cleopatre/application
parentb4059fdaab352000e1bcc8882e4c38d16fd3e1c3 (diff)
cleo/app/igmp_snoopd: Handle effects of IGMP v2 report suppression, refs #2354
Because of v2 report suppression, a v2 member may appear inactive while it's not. It may just have repeatedly suppressed his report because another host answered first to the query. To handle that, we need to identify groups that have a v2 host member and apply a slightly different inactivity detection. For that, we use the [Group Compatibiliy Mode] and the [Older Host Present] defined by the RFC.
Diffstat (limited to 'cleopatre/application')
-rw-r--r--cleopatre/application/igmp_snoopd/inc/data_struct.h4
-rw-r--r--cleopatre/application/igmp_snoopd/inc/internal.h12
-rw-r--r--cleopatre/application/igmp_snoopd/src/data_struct.c6
-rw-r--r--cleopatre/application/igmp_snoopd/src/igmp_common.c42
-rw-r--r--cleopatre/application/igmp_snoopd/src/igmp_v1_v2.c3
5 files changed, 64 insertions, 3 deletions
diff --git a/cleopatre/application/igmp_snoopd/inc/data_struct.h b/cleopatre/application/igmp_snoopd/inc/data_struct.h
index c4c998ecf8..c3ef0ef75f 100644
--- a/cleopatre/application/igmp_snoopd/inc/data_struct.h
+++ b/cleopatre/application/igmp_snoopd/inc/data_struct.h
@@ -69,6 +69,10 @@ struct group
* the timer_end of all its members. */
time_t max_timer_end;
+ /** The time at which the [V2 Host Present Timer] will end.
+ * The [V2 Host Present Timer] is set when a V2 host is seen. */
+ time_t v2_host_present_timer_end;
+
/** Head of the list of members in the group */
LIST_HEAD (list_head_members, group_member) members_head;
diff --git a/cleopatre/application/igmp_snoopd/inc/internal.h b/cleopatre/application/igmp_snoopd/inc/internal.h
index aef9a43215..a9d95df556 100644
--- a/cleopatre/application/igmp_snoopd/inc/internal.h
+++ b/cleopatre/application/igmp_snoopd/inc/internal.h
@@ -26,6 +26,13 @@
#define CMP_MCAST_ETH_ADDR(eth_addr1, eth_addr2) \
(memcmp(&(eth_addr1)[3], &(eth_addr2)[3], 3))
+/** Group compatibility mode. */
+typedef enum
+{
+ GROUP_COMPAT_MODE_IGMP_V2,
+ GROUP_COMPAT_MODE_IGMP_V3
+} group_compatibility_mode_t;
+
/** A duration in seconds */
typedef unsigned int duration_sec_t; /* TODO: unsigned int or double ?*/
@@ -47,8 +54,11 @@ struct igmp_metrics
/** Group Membership Interval. See RFC. */
duration_sec_t group_membership_interval;
- /* Other Querier present Interval. See RFC. */
+ /** Other Querier present Interval. See RFC. */
duration_sec_t other_querier_present_interval;
+
+ /** Older Host Present Interval. See RFC. */
+ duration_sec_t older_host_present_interval;
};
/** The context */
diff --git a/cleopatre/application/igmp_snoopd/src/data_struct.c b/cleopatre/application/igmp_snoopd/src/data_struct.c
index 8beb93a14b..7df92af4f0 100644
--- a/cleopatre/application/igmp_snoopd/src/data_struct.c
+++ b/cleopatre/application/igmp_snoopd/src/data_struct.c
@@ -73,6 +73,7 @@ add_group (struct list_head_groups *groups_head, in_addr_t multicast_addr)
mcast_ip_to_eth_addr (multicast_addr, grp->mapped_eth_addr);
grp->last_report_time = 0;
grp->max_timer_end = 0;
+ grp->v2_host_present_timer_end = 0;
LIST_INIT (&grp->members_head);
grp->member_count = 0;
@@ -307,8 +308,11 @@ dump_groups (const struct list_head_groups *groups_head)
inet_ntop (AF_INET, &grp->multicast_addr, ip_str, sizeof (ip_str));
log_debug ("Group %s / %s", ip_str, mac_str);
- log_debug (" Last Report Time: %lu", (unsigned long)grp->last_report_time);
+ log_debug (" Last Report Time: %lu",
+ (unsigned long)grp->last_report_time);
log_debug (" Max Timer End: %lu", (unsigned long)grp->max_timer_end);
+ log_debug (" V2 Host Present Timer End: %lu",
+ (unsigned long)grp->v2_host_present_timer_end);
log_debug (" ");
log_debug (" %u member(s):", grp->member_count);
diff --git a/cleopatre/application/igmp_snoopd/src/igmp_common.c b/cleopatre/application/igmp_snoopd/src/igmp_common.c
index 796d3fc1f9..7b96b455b8 100644
--- a/cleopatre/application/igmp_snoopd/src/igmp_common.c
+++ b/cleopatre/application/igmp_snoopd/src/igmp_common.c
@@ -118,6 +118,19 @@ compute_group_membership_interval (const struct igmp_metrics *metrics)
}
/**
+ * Compute the value of the [Older Host Present Interval] using the provided
+ * metrics.
+ * \param metrics The metrics.
+ * \return The [Older Host Present Interval]
+ */
+static duration_sec_t
+compute_older_host_present_interval (const struct igmp_metrics *metrics)
+{
+ return (duration_sec_t) ((metrics->robustness_variable * metrics->query_interval)
+ + metrics->query_response_interval);
+}
+
+/**
* Update the computed metrics.
*
* Some of the metrics are computed from the values of other metrics.
@@ -133,6 +146,9 @@ update_computed_metrics (struct igmp_metrics *metrics)
metrics->group_membership_interval =
compute_group_membership_interval (metrics);
+
+ metrics->older_host_present_interval =
+ compute_older_host_present_interval (metrics);
}
void
@@ -174,6 +190,20 @@ is_querier_present (const struct igmp_metrics *metrics)
<= metrics->other_querier_present_interval);
}
+static group_compatibility_mode_t
+group_compat_mode (const struct group *grp, time_t now)
+{
+ if ((grp->v2_host_present_timer_end == 0)
+ || (now > grp->v2_host_present_timer_end))
+ {
+ return GROUP_COMPAT_MODE_IGMP_V3;
+ }
+ else
+ {
+ return GROUP_COMPAT_MODE_IGMP_V2;
+ }
+}
+
void
del_inactive (struct context *ctx)
{
@@ -201,8 +231,16 @@ del_inactive (struct context *ctx)
{
del_group (grp);
}
- else
+ else if (group_compat_mode (grp, now) == GROUP_COMPAT_MODE_IGMP_V3)
{
+ /* We only look for inactive members if the group is in V3 compat
+ * mode.
+ * If the group is in V2 compatibility mode, it means it has some
+ * IGMPv2 members. Because v2 members may suppress their answer to
+ * a query if they see an answer report sent by another host for
+ * the same group, we can not determine that they are inactive in
+ * the same way we do for IGMPv3 hosts. */
+
struct group_member *member = LIST_FIRST (&grp->members_head);
while (member)
{
@@ -252,5 +290,7 @@ dump_info (const struct igmp_metrics *metrics)
(unsigned long)metrics->group_membership_interval);
log_debug ("Other Querier Present Interval: %lu",
(unsigned long)metrics->other_querier_present_interval);
+ log_debug ("Older Host Present Interval: %lu",
+ (unsigned long)metrics->older_host_present_interval);
log_debug ("Querier present: %s", is_querier_present (metrics) ? "yes":"no");
}
diff --git a/cleopatre/application/igmp_snoopd/src/igmp_v1_v2.c b/cleopatre/application/igmp_snoopd/src/igmp_v1_v2.c
index 98cc2fe269..04df6056fe 100644
--- a/cleopatre/application/igmp_snoopd/src/igmp_v1_v2.c
+++ b/cleopatre/application/igmp_snoopd/src/igmp_v1_v2.c
@@ -86,6 +86,9 @@ process_v2_report (struct context *ctx,
update_timers (grp, member, &ctx->metrics);
+ grp->v2_host_present_timer_end =
+ time_now() + ctx->metrics.older_host_present_interval;
+
member->filter_mode = FILTER_MODE_EXCLUDE;
group_member_set_sources (member, NULL, 0);
}