===================================================================
@@ -124,17 +124,40 @@
/* Control of unsolilcited reports (after join) */
-#define IGMP_Unsolicited_Report_Count 2
+#define IGMP_Unsolicited_Report_Count 6
#define IGMP_Initial_Report_Delay (1)
#define IGMP_Unsolicited_Report_Min_Delay (HZ/25)
+#define IGMP_Unsolicited_Fuzz (HZ/100)
+
/* IGMP_Initial_Report_Delay is not from IGMP specs!
* IGMP specs require to report membership immediately after
* joining a group, but we delay the first report by a
* small interval. It seems more natural and still does not
* contradict to specs provided this delay is small enough.
+ *
+ * The spec does not say how the initial igmp reports
+ * need to be repeated (aside from suggesting to just do the
+ * randomization of the intervals as for igmp queries but then
+ * there is no centralized trigger and therefore no randomization
+ * needed). We provide an array of delays here that are likely
+ * to work in general avoiding the often too short or too long intervals
+ * that would be generated if we would follow the suggestion in the rfc.
+ *
+ * Note that the sending of unsolicited reports may stop at any point
+ * if we see an igmp query from a router or a neighbors ignmp report.
*/
+static int unsolicited_delay[IGMP_Unsolicited_Report_Count + 1] = {
+ IGMP_Initial_Report_Delay + IGMP_Mininum_Delay, /* "Immediate" */
+ HZ / 25, /* 40ms */
+ HZ / 5, /* 200ms */
+ HZ,
+ 5 * HZ,
+ 10 * HZ,
+ 60 * HZ
+};
+
#define IGMP_V1_SEEN(in_dev) \
(IPV4_DEVCONF_ALL(dev_net(in_dev->dev), FORCE_IGMP_VERSION) == 1 || \
IN_DEV_CONF_GET((in_dev), FORCE_IGMP_VERSION) == 1 || \
@@ -199,6 +222,13 @@ static void igmp_start_timer(struct ip_m
atomic_inc(&im->refcnt);
}
+static void igmp_start_initial_timer(struct ip_mc_list *im, int interval)
+{
+ int delay = unsolicited_delay[interval];
+
+ igmp_start_timer(im, delay, delay + IGMP_Unsolicited_Fuzz);
+}
+
static void igmp_gq_start_timer(struct in_device *in_dev)
{
in_dev->mr_gq_running = 1;
@@ -748,8 +778,8 @@ static void igmp_timer_expire(unsigned l
if (im->unsolicit_count) {
im->unsolicit_count--;
- igmp_start_timer(im, IGMP_Unsolicited_Report_Min_Delay,
- IGMP_Unsolicited_Report_Interval);
+ igmp_start_initial_timer(im,
+ IGMP_Unsolicited_Report_Count - im->unsolicit_count);
}
im->reporter = 1;
spin_unlock(&im->lock);
@@ -1185,7 +1215,7 @@ static void igmp_group_added(struct ip_m
return;
if (IGMP_V1_SEEN(in_dev) || IGMP_V2_SEEN(in_dev)) {
spin_lock_bh(&im->lock);
- igmp_start_timer(im, IGMP_Mininum_Delay, IGMP_Initial_Report_Delay);
+ igmp_start_initial_timer(im, 0);
spin_unlock_bh(&im->lock);
return;
}