diff options
author | udpa <none@none> | 2007-08-02 16:41:46 -0700 |
---|---|---|
committer | udpa <none@none> | 2007-08-02 16:41:46 -0700 |
commit | 8dc47d9fe24422865d33012b2ca474257537f764 (patch) | |
tree | 8a3df1fd2bfcf85b0ac61dac3537feae51ef6a6a | |
parent | 305057750b3b0e3f43c20466b136ea7933c3d50f (diff) | |
download | illumos-joyent-8dc47d9fe24422865d33012b2ca474257537f764.tar.gz |
6482459 Add options to set IGMP and MLD version to be used on Join requests
6546036 igmp and mld membership reports takes longer than Max Response Time
-rw-r--r-- | usr/src/uts/common/inet/ip.h | 4 | ||||
-rw-r--r-- | usr/src/uts/common/inet/ip/igmp.c | 269 | ||||
-rw-r--r-- | usr/src/uts/common/inet/ip/ip.c | 2 | ||||
-rw-r--r-- | usr/src/uts/common/inet/ip/ip_if.c | 5 | ||||
-rw-r--r-- | usr/src/uts/common/inet/ip_stack.h | 4 |
5 files changed, 164 insertions, 120 deletions
diff --git a/usr/src/uts/common/inet/ip.h b/usr/src/uts/common/inet/ip.h index 27b55cb3cb..851bce464f 100644 --- a/usr/src/uts/common/inet/ip.h +++ b/usr/src/uts/common/inet/ip.h @@ -2964,7 +2964,9 @@ extern vmem_t *ip_minor_arena; #define ips_ip_dup_recovery ips_param_arr[54].ip_param_value #define ips_ip_restrict_interzone_loopback ips_param_arr[55].ip_param_value #define ips_ip_lso_outbound ips_param_arr[56].ip_param_value -#define ips_ipv6_drop_inbound_icmpv6 ips_param_arr[57].ip_param_value +#define ips_igmp_max_version ips_param_arr[57].ip_param_value +#define ips_mld_max_version ips_param_arr[58].ip_param_value +#define ips_ipv6_drop_inbound_icmpv6 ips_param_arr[59].ip_param_value extern int dohwcksum; /* use h/w cksum if supported by the h/w */ #ifdef ZC_TEST diff --git a/usr/src/uts/common/inet/ip/igmp.c b/usr/src/uts/common/inet/ip/igmp.c index f3ccce60b8..ff11a69e8c 100644 --- a/usr/src/uts/common/inet/ip/igmp.c +++ b/usr/src/uts/common/inet/ip/igmp.c @@ -99,6 +99,28 @@ static mrec_t *mcast_merge_rtx(ilm_t *ilm, mrec_t *rp, slist_t *flist); #define SEC_TO_MSEC(sec) ((sec) * 1000) /* + * A running timer (scheduled thru timeout) can be cancelled if another + * timer with a shorter timeout value is scheduled before it has timed + * out. When the shorter timer expires, the original timer is updated + * to account for the time elapsed while the shorter timer ran; but this + * does not take into account the amount of time already spent in timeout + * state before being preempted by the shorter timer, that is the time + * interval between time scheduled to time cancelled. This can cause + * delays in sending out multicast membership reports. To resolve this + * problem, wallclock time (absolute time) is used instead of deltas + * (relative time) to track timers. + * + * The MACRO below gets the lbolt value, used for proper timer scheduling + * and firing. Therefore multicast membership reports are sent on time. + * The timer does not exactly fire at the time it was scehduled to fire, + * there is a difference of a few milliseconds observed. An offset is used + * to take care of the difference. + */ + +#define CURRENT_MSTIME ((uint_t)TICK_TO_MSEC(ddi_get_lbolt())) +#define CURRENT_OFFSET (999) + +/* * The first multicast join will trigger the igmp timers / mld timers * The unit for next is milliseconds. */ @@ -134,6 +156,7 @@ igmp_start_timers(unsigned next, ip_stack_t *ipst) ipst->ips_igmp_time_to_next = next; ipst->ips_igmp_timeout_id = timeout(igmp_timeout_handler, (void *)ipst, MSEC_TO_TICK(ipst->ips_igmp_time_to_next)); + ipst->ips_igmp_timer_scheduled_last = ddi_get_lbolt(); ipst->ips_igmp_timer_setter_active = B_FALSE; mutex_exit(&ipst->ips_igmp_timer_lock); return; @@ -145,7 +168,7 @@ igmp_start_timers(unsigned next, ip_stack_t *ipst) * reschedule the timeout if the new 'next' will happen * earlier than the currently scheduled timeout */ - time_left = ipst->ips_igmp_timer_fired_last + + time_left = ipst->ips_igmp_timer_scheduled_last + MSEC_TO_TICK(ipst->ips_igmp_time_to_next) - ddi_get_lbolt(); if (time_left < MSEC_TO_TICK(next)) { ipst->ips_igmp_timer_setter_active = B_FALSE; @@ -176,6 +199,7 @@ igmp_start_timers(unsigned next, ip_stack_t *ipst) MIN(ipst->ips_igmp_time_to_next, next); ipst->ips_igmp_timeout_id = timeout(igmp_timeout_handler, (void *)ipst, MSEC_TO_TICK(ipst->ips_igmp_time_to_next)); + ipst->ips_igmp_timer_scheduled_last = ddi_get_lbolt(); } ipst->ips_igmp_timer_setter_active = B_FALSE; mutex_exit(&ipst->ips_igmp_timer_lock); @@ -216,6 +240,7 @@ mld_start_timers(unsigned next, ip_stack_t *ipst) ipst->ips_mld_time_to_next = next; ipst->ips_mld_timeout_id = timeout(mld_timeout_handler, (void *)ipst, MSEC_TO_TICK(ipst->ips_mld_time_to_next)); + ipst->ips_mld_timer_scheduled_last = ddi_get_lbolt(); ipst->ips_mld_timer_setter_active = B_FALSE; mutex_exit(&ipst->ips_mld_timer_lock); return; @@ -227,7 +252,7 @@ mld_start_timers(unsigned next, ip_stack_t *ipst) * reschedule the timeout if the new 'next' will happen * earlier than the currently scheduled timeout */ - time_left = ipst->ips_mld_timer_fired_last + + time_left = ipst->ips_mld_timer_scheduled_last + MSEC_TO_TICK(ipst->ips_mld_time_to_next) - ddi_get_lbolt(); if (time_left < MSEC_TO_TICK(next)) { ipst->ips_mld_timer_setter_active = B_FALSE; @@ -258,6 +283,7 @@ mld_start_timers(unsigned next, ip_stack_t *ipst) MIN(ipst->ips_mld_time_to_next, next); ipst->ips_mld_timeout_id = timeout(mld_timeout_handler, (void *)ipst, MSEC_TO_TICK(ipst->ips_mld_time_to_next)); + ipst->ips_mld_timer_scheduled_last = ddi_get_lbolt(); } ipst->ips_mld_timer_setter_active = B_FALSE; mutex_exit(&ipst->ips_mld_timer_lock); @@ -340,7 +366,8 @@ igmp_input(queue_t *q, mblk_t *mp, ill_t *ill) * packet length differentiates between v1/v2 and v3 * v1/v2 should be exactly 8 octets long; v3 is >= 12 */ - if (igmplen == IGMP_MINLEN) { + if ((igmplen == IGMP_MINLEN) || + (ipst->ips_igmp_max_version <= IGMP_V2_ROUTER)) { next = igmp_query_in(ipha, igmpa, ill); } else if (igmplen >= IGMP_V3_QUERY_MINLEN) { next = igmpv3_query_in((igmp3qa_t *)igmpa, ill, @@ -458,7 +485,7 @@ igmp_query_in(ipha_t *ipha, igmpa_t *igmpa, ill_t *ill) { ilm_t *ilm; int timer; - uint_t next; + uint_t next, current; ip_stack_t *ipst; ipst = ill->ill_ipst; @@ -476,7 +503,8 @@ igmp_query_in(ipha_t *ipha, igmpa_t *igmpa, ill_t *ill) * we have heard a report from another member, or IGMP_IREPORTEDLAST * if I sent the last report. */ - if (igmpa->igmpa_code == 0) { + if ((igmpa->igmpa_code == 0) || + (ipst->ips_igmp_max_version == IGMP_V1_ROUTER)) { /* * Query from an old router. * Remember that the querier on this interface is old, @@ -558,6 +586,8 @@ igmp_query_in(ipha_t *ipha, igmpa_t *igmpa, ill_t *ill) */ next = (unsigned)INFINITY; mutex_enter(&ill->ill_lock); + + current = CURRENT_MSTIME; for (ilm = ill->ill_ilm; ilm; ilm = ilm->ilm_next) { /* @@ -577,6 +607,7 @@ igmp_query_in(ipha_t *ipha, igmpa_t *igmpa, ill_t *ill) MCAST_RANDOM_DELAY(ilm->ilm_timer, timer); if (ilm->ilm_timer < next) next = ilm->ilm_timer; + ilm->ilm_timer += current; } } } @@ -589,6 +620,7 @@ static uint_t igmpv3_query_in(igmp3qa_t *igmp3qa, ill_t *ill, int igmplen) { uint_t i, next, mrd, qqi, timer, delay, numsrc; + uint_t current; ilm_t *ilm; ipaddr_t *src_array; uint8_t qrv; @@ -617,6 +649,7 @@ igmpv3_query_in(igmp3qa_t *igmp3qa, ill_t *ill, int igmplen) timer = DSEC_TO_MSEC(mrd); MCAST_RANDOM_DELAY(delay, timer); next = (unsigned)INFINITY; + current = CURRENT_MSTIME; if ((qrv = igmp3qa->igmp3qa_sqrv & IGMP_V3_RV_MASK) == 0) ill->ill_mcast_rv = MCAST_DEF_ROBUSTNESS; @@ -638,7 +671,7 @@ igmpv3_query_in(igmp3qa_t *igmp3qa, ill_t *ill, int igmplen) * no action is required (RFC3376 section 5.2 rule 1) */ mutex_enter(&ill->ill_lock); - if (ill->ill_global_timer < delay) { + if (ill->ill_global_timer < (current + delay)) { mutex_exit(&ill->ill_lock); return (next); } @@ -656,9 +689,9 @@ igmpv3_query_in(igmp3qa_t *igmp3qa, ill_t *ill, int igmplen) * our delay (random value in range [0, response time]). */ mutex_enter(&ill->ill_lock); - ill->ill_global_timer = delay; - next = ill->ill_global_timer; + ill->ill_global_timer = current + delay; mutex_exit(&ill->ill_lock); + next = delay; } else { /* group or group/source specific query */ @@ -708,10 +741,14 @@ group_query: if (overflow) goto group_query; } + + ilm->ilm_timer = (ilm->ilm_timer == INFINITY) ? + INFINITY : (ilm->ilm_timer - current); /* choose soonest timer */ ilm->ilm_timer = MIN(ilm->ilm_timer, delay); if (ilm->ilm_timer < next) next = ilm->ilm_timer; + ilm->ilm_timer += current; } mutex_exit(&ill->ill_lock); } @@ -722,6 +759,7 @@ group_query: void igmp_joingroup(ilm_t *ilm) { + uint_t timer; ill_t *ill; ip_stack_t *ipst = ilm->ilm_ipst; @@ -777,6 +815,8 @@ igmp_joingroup(ilm_t *ilm) /* Set the ilm timer value */ MCAST_RANDOM_DELAY(ilm->ilm_rtx.rtx_timer, SEC_TO_MSEC(IGMP_MAX_HOST_REPORT_DELAY)); + timer = ilm->ilm_rtx.rtx_timer; + ilm->ilm_rtx.rtx_timer += CURRENT_MSTIME; ilm->ilm_state = IGMP_IREPORTEDLAST; mutex_exit(&ill->ill_lock); @@ -789,7 +829,7 @@ igmp_joingroup(ilm_t *ilm) * out of the ipsq in ipsq_exit. */ mutex_enter(&ipst->ips_igmp_timer_lock); - ipst->ips_igmp_deferred_next = MIN(ilm->ilm_rtx.rtx_timer, + ipst->ips_igmp_deferred_next = MIN(timer, ipst->ips_igmp_deferred_next); mutex_exit(&ipst->ips_igmp_timer_lock); } @@ -798,13 +838,14 @@ igmp_joingroup(ilm_t *ilm) (void) mi_strlog(ilm->ilm_ipif->ipif_ill->ill_rq, 1, SL_TRACE, "igmp_joingroup: multicast_type %d timer %d", (ilm->ilm_ipif->ipif_ill->ill_mcast_type), - (int)ntohl(ilm->ilm_rtx.rtx_timer)); + (int)ntohl(timer)); } } void mld_joingroup(ilm_t *ilm) { + uint_t timer; ill_t *ill; ip_stack_t *ipst = ilm->ilm_ipst; @@ -856,6 +897,8 @@ mld_joingroup(ilm_t *ilm) ilm->ilm_rtx.rtx_cnt > 0); MCAST_RANDOM_DELAY(ilm->ilm_rtx.rtx_timer, SEC_TO_MSEC(ICMP6_MAX_HOST_REPORT_DELAY)); + timer = ilm->ilm_rtx.rtx_timer; + ilm->ilm_rtx.rtx_timer += CURRENT_MSTIME; ilm->ilm_state = IGMP_IREPORTEDLAST; mutex_exit(&ill->ill_lock); @@ -868,7 +911,7 @@ mld_joingroup(ilm_t *ilm) * out of the ipsq in ipsq_exit */ mutex_enter(&ipst->ips_mld_timer_lock); - ipst->ips_mld_deferred_next = MIN(ilm->ilm_rtx.rtx_timer, + ipst->ips_mld_deferred_next = MIN(timer, ipst->ips_mld_deferred_next); mutex_exit(&ipst->ips_mld_timer_lock); } @@ -877,7 +920,7 @@ mld_joingroup(ilm_t *ilm) (void) mi_strlog(ilm->ilm_ill->ill_rq, 1, SL_TRACE, "mld_joingroup: multicast_type %d timer %d", (ilm->ilm_ill->ill_mcast_type), - (int)ntohl(ilm->ilm_rtx.rtx_timer)); + (int)ntohl(timer)); } } @@ -1050,6 +1093,7 @@ send_to_in: mutex_enter(&ipst->ips_igmp_timer_lock); ipst->ips_igmp_deferred_next = MIN(ipst->ips_igmp_deferred_next, ilm->ilm_rtx.rtx_timer); + ilm->ilm_rtx.rtx_timer += CURRENT_MSTIME; mutex_exit(&ipst->ips_igmp_timer_lock); } @@ -1138,6 +1182,7 @@ send_to_in: mutex_enter(&ipst->ips_mld_timer_lock); ipst->ips_mld_deferred_next = MIN(ipst->ips_mld_deferred_next, ilm->ilm_rtx.rtx_timer); + ilm->ilm_rtx.rtx_timer += CURRENT_MSTIME; mutex_exit(&ipst->ips_mld_timer_lock); } @@ -1146,9 +1191,9 @@ send_to_in: } uint_t -igmp_timeout_handler_per_ill(ill_t *ill, int elapsed) +igmp_timeout_handler_per_ill(ill_t *ill) { - uint_t next = INFINITY; + uint_t next = INFINITY, current; ilm_t *ilm; ipif_t *ipif; mrec_t *rp = NULL; @@ -1160,10 +1205,11 @@ igmp_timeout_handler_per_ill(ill_t *ill, int elapsed) mutex_enter(&ill->ill_lock); + current = CURRENT_MSTIME; /* First check the global timer on this interface */ if (ill->ill_global_timer == INFINITY) goto per_ilm_timer; - if (ill->ill_global_timer <= elapsed) { + if (ill->ill_global_timer <= (current + CURRENT_OFFSET)) { ill->ill_global_timer = INFINITY; /* * Send report for each group on this interface. @@ -1204,9 +1250,8 @@ igmp_timeout_handler_per_ill(ill_t *ill, int elapsed) ipif->ipif_igmp_rpt = NULL; } } else { - ill->ill_global_timer -= elapsed; - if (ill->ill_global_timer < next) - next = ill->ill_global_timer; + if ((ill->ill_global_timer - current) < next) + next = ill->ill_global_timer - current; } per_ilm_timer: @@ -1214,16 +1259,15 @@ per_ilm_timer: if (ilm->ilm_timer == INFINITY) goto per_ilm_rtxtimer; - if (ilm->ilm_timer > elapsed) { - ilm->ilm_timer -= elapsed; - if (ilm->ilm_timer < next) - next = ilm->ilm_timer; + if (ilm->ilm_timer > (current + CURRENT_OFFSET)) { + if ((ilm->ilm_timer - current) < next) + next = ilm->ilm_timer - current; if (ip_debug > 1) { (void) mi_strlog(ill->ill_rq, 1, SL_TRACE, - "igmp_timo_hlr 2: ilm_timr %d elap %d " + "igmp_timo_hlr 2: ilm_timr %d " "typ %d nxt %d", - (int)ntohl(ilm->ilm_timer), elapsed, + (int)ntohl(ilm->ilm_timer - current), (ill->ill_mcast_type), next); } @@ -1277,23 +1321,14 @@ per_ilm_timer: rp = NULL; } - if (ip_debug > 1) { - (void) mi_strlog(ill->ill_rq, 1, SL_TRACE, - "igmp_timo_hlr 1: ilm_timr %d elap %d " - "typ %d nxt %d", - (int)ntohl(ilm->ilm_timer), elapsed, - (ill->ill_mcast_type), next); - } - per_ilm_rtxtimer: rtxp = &ilm->ilm_rtx; if (rtxp->rtx_timer == INFINITY) continue; - if (rtxp->rtx_timer > elapsed) { - rtxp->rtx_timer -= elapsed; - if (rtxp->rtx_timer < next) - next = rtxp->rtx_timer; + if (rtxp->rtx_timer > (current + CURRENT_OFFSET)) { + if ((rtxp->rtx_timer - current) < next) + next = rtxp->rtx_timer - current; continue; } @@ -1342,6 +1377,7 @@ per_ilm_rtxtimer: SEC_TO_MSEC(IGMP_MAX_HOST_REPORT_DELAY)); if (rtxp->rtx_timer < next) next = rtxp->rtx_timer; + rtxp->rtx_timer += current; } else { CLEAR_SLIST(rtxp->rtx_allow); CLEAR_SLIST(rtxp->rtx_block); @@ -1385,7 +1421,6 @@ void igmp_timeout_handler(void *arg) { ill_t *ill; - int elapsed; /* Since last call */ uint_t global_next = INFINITY; uint_t next; ill_walk_context_t ctx; @@ -1395,8 +1430,7 @@ igmp_timeout_handler(void *arg) ASSERT(arg != NULL); mutex_enter(&ipst->ips_igmp_timer_lock); ASSERT(ipst->ips_igmp_timeout_id != 0); - ipst->ips_igmp_timer_fired_last = ddi_get_lbolt(); - elapsed = ipst->ips_igmp_time_to_next; + ipst->ips_igmp_timer_scheduled_last = 0; ipst->ips_igmp_time_to_next = 0; mutex_exit(&ipst->ips_igmp_timer_lock); @@ -1414,7 +1448,7 @@ igmp_timeout_handler(void *arg) rw_exit(&ipst->ips_ill_g_lock); success = ipsq_enter(ill, B_TRUE); if (success) { - next = igmp_timeout_handler_per_ill(ill, elapsed); + next = igmp_timeout_handler_per_ill(ill); if (next < global_next) global_next = next; ipsq_exit(ill->ill_phyint->phyint_ipsq, B_FALSE, @@ -1441,10 +1475,10 @@ igmp_timeout_handler(void *arg) */ /* ARGSUSED */ uint_t -mld_timeout_handler_per_ill(ill_t *ill, int elapsed) +mld_timeout_handler_per_ill(ill_t *ill) { ilm_t *ilm; - uint_t next = INFINITY; + uint_t next = INFINITY, current; mrec_t *rp, *rtxrp; rtx_state_t *rtxp; mcast_record_t rtype; @@ -1453,13 +1487,14 @@ mld_timeout_handler_per_ill(ill_t *ill, int elapsed) mutex_enter(&ill->ill_lock); + current = CURRENT_MSTIME; /* * First check the global timer on this interface; the global timer * is not used for MLDv1, so if it's set we can assume we're v2. */ if (ill->ill_global_timer == INFINITY) goto per_ilm_timer; - if (ill->ill_global_timer <= elapsed) { + if (ill->ill_global_timer <= (current + CURRENT_OFFSET)) { ill->ill_global_timer = INFINITY; /* * Send report for each group on this interface. @@ -1489,9 +1524,8 @@ mld_timeout_handler_per_ill(ill_t *ill, int elapsed) mldv2_sendrpt(ill, rp); mutex_enter(&ill->ill_lock); } else { - ill->ill_global_timer -= elapsed; - if (ill->ill_global_timer < next) - next = ill->ill_global_timer; + if ((ill->ill_global_timer - current) < next) + next = ill->ill_global_timer - current; } per_ilm_timer: @@ -1500,16 +1534,15 @@ per_ilm_timer: if (ilm->ilm_timer == INFINITY) goto per_ilm_rtxtimer; - if (ilm->ilm_timer > elapsed) { - ilm->ilm_timer -= elapsed; - if (ilm->ilm_timer < next) - next = ilm->ilm_timer; + if (ilm->ilm_timer > (current + CURRENT_OFFSET)) { + if ((ilm->ilm_timer - current) < next) + next = ilm->ilm_timer - current; if (ip_debug > 1) { (void) mi_strlog(ill->ill_rq, 1, SL_TRACE, "igmp_timo_hlr 2: ilm_timr" - " %d elap %d typ %d nxt %d", - (int)ntohl(ilm->ilm_timer), elapsed, + " %d typ %d nxt %d", + (int)ntohl(ilm->ilm_timer - current), (ill->ill_mcast_type), next); } @@ -1550,23 +1583,14 @@ per_ilm_timer: } } - if (ip_debug > 1) { - (void) mi_strlog(ill->ill_rq, 1, SL_TRACE, - "igmp_timo_hlr 1: ilm_timr %d elap %d " - "typ %d nxt %d", - (int)ntohl(ilm->ilm_timer), elapsed, - (ill->ill_mcast_type), next); - } - per_ilm_rtxtimer: rtxp = &ilm->ilm_rtx; if (rtxp->rtx_timer == INFINITY) continue; - if (rtxp->rtx_timer > elapsed) { - rtxp->rtx_timer -= elapsed; - if (rtxp->rtx_timer < next) - next = rtxp->rtx_timer; + if (rtxp->rtx_timer > (current + CURRENT_OFFSET)) { + if ((rtxp->rtx_timer - current) < next) + next = rtxp->rtx_timer - current; continue; } @@ -1610,6 +1634,7 @@ per_ilm_rtxtimer: SEC_TO_MSEC(ICMP6_MAX_HOST_REPORT_DELAY)); if (rtxp->rtx_timer < next) next = rtxp->rtx_timer; + rtxp->rtx_timer += current; } else { CLEAR_SLIST(rtxp->rtx_allow); CLEAR_SLIST(rtxp->rtx_block); @@ -1638,7 +1663,6 @@ void mld_timeout_handler(void *arg) { ill_t *ill; - int elapsed; /* Since last call */ uint_t global_next = INFINITY; uint_t next; ill_walk_context_t ctx; @@ -1648,8 +1672,7 @@ mld_timeout_handler(void *arg) ASSERT(arg != NULL); mutex_enter(&ipst->ips_mld_timer_lock); ASSERT(ipst->ips_mld_timeout_id != 0); - ipst->ips_mld_timer_fired_last = ddi_get_lbolt(); - elapsed = ipst->ips_mld_time_to_next; + ipst->ips_mld_timer_scheduled_last = 0; ipst->ips_mld_time_to_next = 0; mutex_exit(&ipst->ips_mld_timer_lock); @@ -1667,7 +1690,7 @@ mld_timeout_handler(void *arg) rw_exit(&ipst->ips_ill_g_lock); success = ipsq_enter(ill, B_TRUE); if (success) { - next = mld_timeout_handler_per_ill(ill, elapsed); + next = mld_timeout_handler_per_ill(ill); if (next < global_next) global_next = next; ipsq_exit(ill->ill_phyint->phyint_ipsq, B_TRUE, @@ -1700,6 +1723,8 @@ mld_timeout_handler(void *arg) * - Resets to new router if we didnt we hear from the router * in IGMP_AGE_THRESHOLD seconds. * - Resets slowtimeout. + * Check for ips_igmp_max_version ensures that we don't revert to a higher + * IGMP version than configured. */ void igmp_slowtimo(void *arg) @@ -1740,42 +1765,43 @@ igmp_slowtimo(void *arg) ill->ill_mcast_v1_time++; if (ill->ill_mcast_v2_tset == 1) ill->ill_mcast_v2_time++; - if (ill->ill_mcast_type == IGMP_V1_ROUTER) { - if (ill->ill_mcast_v1_time >= OVQP(ill)) { - if (ill->ill_mcast_v2_tset > 0) { - ip1dbg(("V1 query timer " - "expired on %s; switching " - "mode to IGMP_V2\n", - ill->ill_name)); - ill->ill_mcast_type = - IGMP_V2_ROUTER; - } else { - ip1dbg(("V1 query timer " - "expired on %s; switching " - "mode to IGMP_V3\n", - ill->ill_name)); - ill->ill_mcast_type = - IGMP_V3_ROUTER; - } - ill->ill_mcast_v1_time = 0; - ill->ill_mcast_v1_tset = 0; - atomic_add_16(&ifp->illif_mcast_v1, -1); - } - } - if (ill->ill_mcast_type == IGMP_V2_ROUTER) { - if (ill->ill_mcast_v2_time >= OVQP(ill)) { - ip1dbg(("V2 query timer expired on " - "%s; switching mode to IGMP_V3\n", + if ((ill->ill_mcast_type == IGMP_V1_ROUTER) && + (ipst->ips_igmp_max_version >= IGMP_V2_ROUTER) && + (ill->ill_mcast_v1_time >= OVQP(ill))) { + if ((ill->ill_mcast_v2_tset > 0) || + (ipst->ips_igmp_max_version == + IGMP_V2_ROUTER)) { + ip1dbg(("V1 query timer " + "expired on %s; switching " + "mode to IGMP_V2\n", + ill->ill_name)); + ill->ill_mcast_type = + IGMP_V2_ROUTER; + } else { + ip1dbg(("V1 query timer " + "expired on %s; switching " + "mode to IGMP_V3\n", ill->ill_name)); - ill->ill_mcast_type = IGMP_V3_ROUTER; - ill->ill_mcast_v2_time = 0; - ill->ill_mcast_v2_tset = 0; - atomic_add_16(&ifp->illif_mcast_v2, -1); + ill->ill_mcast_type = + IGMP_V3_ROUTER; } + ill->ill_mcast_v1_time = 0; + ill->ill_mcast_v1_tset = 0; + atomic_add_16(&ifp->illif_mcast_v1, -1); + } + if ((ill->ill_mcast_type == IGMP_V2_ROUTER) && + (ipst->ips_igmp_max_version >= IGMP_V3_ROUTER) && + (ill->ill_mcast_v2_time >= OVQP(ill))) { + ip1dbg(("V2 query timer expired on " + "%s; switching mode to IGMP_V3\n", + ill->ill_name)); + ill->ill_mcast_type = IGMP_V3_ROUTER; + ill->ill_mcast_v2_time = 0; + ill->ill_mcast_v2_tset = 0; + atomic_add_16(&ifp->illif_mcast_v2, -1); } mutex_exit(&ill->ill_lock); } - } rw_exit(&ipst->ips_ill_g_lock); mutex_enter(&ipst->ips_igmp_slowtimeout_lock); @@ -1789,6 +1815,8 @@ igmp_slowtimo(void *arg) * - Resets to newer version if we didn't hear from the older version router * in MLD_AGE_THRESHOLD seconds. * - Restarts slowtimeout. + * Check for ips_mld_max_version ensures that we don't revert to a higher + * IGMP version than configured. */ /* ARGSUSED */ void @@ -1814,16 +1842,16 @@ mld_slowtimo(void *arg) mutex_enter(&ill->ill_lock); if (ill->ill_mcast_v1_tset == 1) ill->ill_mcast_v1_time++; - if (ill->ill_mcast_type == MLD_V1_ROUTER) { - if (ill->ill_mcast_v1_time >= OVQP(ill)) { - ip1dbg(("MLD query timer expired on" - " %s; switching mode to MLD_V2\n", - ill->ill_name)); - ill->ill_mcast_type = MLD_V2_ROUTER; - ill->ill_mcast_v1_time = 0; - ill->ill_mcast_v1_tset = 0; - atomic_add_16(&ifp->illif_mcast_v1, -1); - } + if ((ill->ill_mcast_type == MLD_V1_ROUTER) && + (ipst->ips_mld_max_version >= MLD_V2_ROUTER) && + (ill->ill_mcast_v1_time >= OVQP(ill))) { + ip1dbg(("MLD query timer expired on" + " %s; switching mode to MLD_V2\n", + ill->ill_name)); + ill->ill_mcast_type = MLD_V2_ROUTER; + ill->ill_mcast_v1_time = 0; + ill->ill_mcast_v1_tset = 0; + atomic_add_16(&ifp->illif_mcast_v1, -1); } mutex_exit(&ill->ill_lock); } @@ -2209,7 +2237,8 @@ mld_input(queue_t *q, mblk_t *mp, ill_t *ill) * packet length differentiates between v1 and v2. v1 * query should be exactly 24 octets long; v2 is >= 28. */ - if (mldlen == MLD_MINLEN) { + if ((mldlen == MLD_MINLEN) || + (ipst->ips_mld_max_version < MLD_V2_ROUTER)) { next = mld_query_in(mldh, ill); } else if (mldlen >= MLD_V2_QUERY_MINLEN) { next = mldv2_query_in((mld2q_t *)mldh, ill, mldlen); @@ -2320,7 +2349,7 @@ mld_query_in(mld_hdr_t *mldh, ill_t *ill) { ilm_t *ilm; int timer; - uint_t next; + uint_t next, current; in6_addr_t *v6group; BUMP_MIB(ill->ill_icmp6_mib, ipv6IfIcmpInGroupMembQueries); @@ -2377,6 +2406,8 @@ mld_query_in(mld_hdr_t *mldh, ill_t *ill) */ next = INFINITY; mutex_enter(&ill->ill_lock); + + current = CURRENT_MSTIME; for (ilm = ill->ill_ilm; ilm != NULL; ilm = ilm->ilm_next) { ASSERT(!IN6_IS_ADDR_V4MAPPED(&ilm->ilm_v6addr)); @@ -2401,6 +2432,7 @@ mld_query_in(mld_hdr_t *mldh, ill_t *ill) MCAST_RANDOM_DELAY(ilm->ilm_timer, timer); if (ilm->ilm_timer < next) next = ilm->ilm_timer; + ilm->ilm_timer += current; } break; } @@ -2420,7 +2452,7 @@ mldv2_query_in(mld2q_t *mld2q, ill_t *ill, int mldlen) { ilm_t *ilm; in6_addr_t *v6group, *src_array; - uint_t next, numsrc, i, mrd, delay, qqi; + uint_t next, numsrc, i, mrd, delay, qqi, current; uint8_t qrv; v6group = &mld2q->mld2q_addr; @@ -2444,8 +2476,12 @@ mldv2_query_in(mld2q_t *mld2q, ill_t *ill, int mldlen) exp = (hdrval & MLD_V2_MAXRT_EXP_MASK) >> 12; mrd = (mant | 0x1000) << (exp + 3); } + if (mrd == 0) + mrd = DSEC_TO_MSEC(MCAST_DEF_QUERY_RESP_INTERVAL); + MCAST_RANDOM_DELAY(delay, mrd); next = (unsigned)INFINITY; + current = CURRENT_MSTIME; if ((qrv = mld2q->mld2q_sqrv & MLD_V2_RV_MASK) == 0) ill->ill_mcast_rv = MCAST_DEF_ROBUSTNESS; @@ -2466,7 +2502,7 @@ mldv2_query_in(mld2q_t *mld2q, ill_t *ill, int mldlen) * no action is required (MLDv2 draft section 6.2 rule 1) */ mutex_enter(&ill->ill_lock); - if (ill->ill_global_timer < delay) { + if (ill->ill_global_timer < (current + delay)) { mutex_exit(&ill->ill_lock); return (next); } @@ -2484,9 +2520,9 @@ mldv2_query_in(mld2q_t *mld2q, ill_t *ill, int mldlen) * our delay (random value in range [0, response time]) */ mutex_enter(&ill->ill_lock); - ill->ill_global_timer = delay; - next = ill->ill_global_timer; + ill->ill_global_timer = current + delay; mutex_exit(&ill->ill_lock); + next = delay; } else { /* group or group/source specific query */ @@ -2536,10 +2572,13 @@ group_query: if (overflow) goto group_query; } + ilm->ilm_timer = (ilm->ilm_timer == INFINITY) ? + INFINITY : (ilm->ilm_timer - current); /* set timer to soonest value */ ilm->ilm_timer = MIN(ilm->ilm_timer, delay); if (ilm->ilm_timer < next) next = ilm->ilm_timer; + ilm->ilm_timer += current; break; } mutex_exit(&ill->ill_lock); diff --git a/usr/src/uts/common/inet/ip/ip.c b/usr/src/uts/common/inet/ip/ip.c index eced7da92e..f0783018ba 100644 --- a/usr/src/uts/common/inet/ip/ip.c +++ b/usr/src/uts/common/inet/ip/ip.c @@ -880,6 +880,8 @@ static ipparam_t lcl_param_arr[] = { { 0, 3600000, 300000, "ip_dup_recovery" }, { 0, 1, 1, "ip_restrict_interzone_loopback" }, { 0, 1, 1, "ip_lso_outbound" }, + { IGMP_V1_ROUTER, IGMP_V3_ROUTER, IGMP_V3_ROUTER, "igmp_max_version" }, + { MLD_V1_ROUTER, MLD_V2_ROUTER, MLD_V2_ROUTER, "mld_max_version" }, #ifdef DEBUG { 0, 1, 0, "ip6_drop_inbound_icmpv6" }, #else diff --git a/usr/src/uts/common/inet/ip/ip_if.c b/usr/src/uts/common/inet/ip/ip_if.c index ef9f4e5c86..0fae61a1c1 100644 --- a/usr/src/uts/common/inet/ip/ip_if.c +++ b/usr/src/uts/common/inet/ip/ip_if.c @@ -4821,7 +4821,6 @@ ill_init(queue_t *q, ill_t *ill) ill->ill_ipf_gen = 0; ill->ill_global_timer = INFINITY; - ill->ill_mcast_type = IGMP_V3_ROUTER; /* == MLD_V2_ROUTER */ ill->ill_mcast_v1_time = ill->ill_mcast_v2_time = 0; ill->ill_mcast_v1_tset = ill->ill_mcast_v2_tset = 0; ill->ill_mcast_rv = MCAST_DEF_ROBUSTNESS; @@ -5093,7 +5092,6 @@ ill_lookup_on_name(char *name, boolean_t do_alloc, boolean_t isv6, /* Set ill_name_set for ill_phyint_reinit to work properly */ ill->ill_global_timer = INFINITY; - ill->ill_mcast_type = IGMP_V3_ROUTER; /* == MLD_V2_ROUTER */ ill->ill_mcast_v1_time = ill->ill_mcast_v2_time = 0; ill->ill_mcast_v1_tset = ill->ill_mcast_v2_tset = 0; ill->ill_mcast_rv = MCAST_DEF_ROBUSTNESS; @@ -22956,6 +22954,9 @@ ill_phyint_reinit(ill_t *ill) if (ill->ill_isv6) { ill->ill_icmp6_mib->ipv6IfIcmpIfIndex = ill->ill_phyint->phyint_ifindex; + ill->ill_mcast_type = ipst->ips_mld_max_version; + } else { + ill->ill_mcast_type = ipst->ips_igmp_max_version; } /* diff --git a/usr/src/uts/common/inet/ip_stack.h b/usr/src/uts/common/inet/ip_stack.h index 750cc30d28..500ea14aa8 100644 --- a/usr/src/uts/common/inet/ip_stack.h +++ b/usr/src/uts/common/inet/ip_stack.h @@ -215,7 +215,7 @@ struct ip_stack { /* ip.c */ /* Following protected by ips_igmp_timer_lock */ int ips_igmp_time_to_next; /* Time since last timeout */ - int ips_igmp_timer_fired_last; + int ips_igmp_timer_scheduled_last; int ips_igmp_deferred_next; timeout_id_t ips_igmp_timeout_id; /* Protected by igmp_timer_lock */ @@ -223,7 +223,7 @@ struct ip_stack { /* Following protected by mld_timer_lock */ int ips_mld_time_to_next; /* Time since last timeout */ - int ips_mld_timer_fired_last; + int ips_mld_timer_scheduled_last; int ips_mld_deferred_next; timeout_id_t ips_mld_timeout_id; /* Protected by mld_timer_lock */ |