?? mld6igmp_group_record.cc
字號:
return; } if (is_asm_mode()) { // // Router State: EXCLUDE (X, Y) // Report Received: BLOCK (A) // New Router State: EXCLUDE (X + (A - Y), Y) // Actions: (A - X - Y) = Group Timer // Send Q(G, A - Y) // Mld6igmpSourceSet& a = _do_forward_sources; TimeVal gt; _group_timer.time_remaining(gt); const set<IPvX>& b = sources; Mld6igmpSourceSet a_and_b= a * b; // Send Q(G, A - Y) with a_minus_y _mld6igmp_vif.mld6igmp_group_source_query_send( group(), a_and_b.extract_source_addresses(), dummy_error_msg); calculate_forwarding_changes(old_is_include_mode, old_do_forward_sources); return; }}/** * Lower the group timer. * * @param timeval the timeout interval the timer should be lowered to. */voidMld6igmpGroupRecord::lower_group_timer(const TimeVal& timeval){ TimeVal timeval_remaining; // // Lower the group timer // _group_timer.time_remaining(timeval_remaining); if (timeval < timeval_remaining) { _group_timer = eventloop().new_oneoff_after( timeval, callback(this, &Mld6igmpGroupRecord::group_timer_timeout)); }}/** * Lower the source timer for a set of sources. * * @param sources the source addresses. * @param timeval the timeout interval the timer should be lowered to. */voidMld6igmpGroupRecord::lower_source_timer(const set<IPvX>& sources, const TimeVal& timeval){ // // Lower the source timer // _do_forward_sources.lower_source_timer(sources, timeval);}/** * Take the appropriate actions for a source that has expired. * * @param source_record the source record that has expired. */voidMld6igmpGroupRecord::source_expired(Mld6igmpSourceRecord* source_record){ Mld6igmpSourceSet::iterator iter; // Erase the source record from the appropriate source set iter = _do_forward_sources.find(source_record->source()); XLOG_ASSERT(iter != _do_forward_sources.end()); _do_forward_sources.erase(iter); if (is_include_mode()) { // notify routing (-) mld6igmp_vif().join_prune_notify_routing(source_record->source(), group(), ACTION_PRUNE); // Delete the source record delete source_record; // If no more source records, then delete the group record if (_do_forward_sources.empty()) { mld6igmp_vif().group_records().erase(group()); delete this; } return; } if (is_asm_mode()) { // notify routing (-) // // XXX: Note that we send a PRUNE twice: the first one to remove the // original JOIN for the source, and the second one to create // PRUNE state for the source. // mld6igmp_vif().join_prune_notify_routing(source_record->source(), group(), ACTION_PRUNE); delete source_record; return; }}/** * Get the number of seconds until the group timer expires. * * @return the number of seconds until the group timer expires. */uint32_tMld6igmpGroupRecord::timeout_sec() const{ TimeVal tv; _group_timer.time_remaining(tv); return (tv.sec());}/** * Timeout: the group timer has expired. */voidMld6igmpGroupRecord::group_timer_timeout(){ if (is_include_mode()) { // XXX: Nothing to do when in INCLUDE mode. if (_do_forward_sources.empty()) { mld6igmp_vif().join_prune_notify_routing(IPvX::ZERO(family()), group(), ACTION_PRUNE); mld6igmp_vif().group_records().erase(group()); delete this; } else { mld6igmp_vif().join_prune_notify_routing(IPvX::ZERO(family()), group(), ACTION_PRUNE); } return; } if (is_asm_mode()) { // notify routing (-) mld6igmp_vif().join_prune_notify_routing(IPvX::ZERO(family()), group(), ACTION_PRUNE); if (! _do_forward_sources.empty()) { // Transition to INCLUDE mode return; } // // No sources with running source timers. // Delete the group record and return immediately. // mld6igmp_vif().group_records().erase(group()); delete this; return; }}/** * Schedule periodic Group-Specific and Group-and-Source-Specific Query * retransmission. * * If the sources list is empty, we schedule Group-Specific Query, * otherwise we schedule Group-and-Source-Specific Query. * * @param sources the source addresses. */voidMld6igmpGroupRecord::schedule_periodic_group_query(const set<IPvX>& sources){ Mld6igmpSourceSet::iterator source_iter; size_t count = _mld6igmp_vif.last_member_query_count() - 1; if (_mld6igmp_vif.last_member_query_count() == 0) return; if (_mld6igmp_vif.query_last_member_interval().get() == TimeVal::ZERO()) return; // // Set the count for query retransmissions // if (sources.empty()) { // // Set the count for Group-Specific Query retransmission // _query_retransmission_count = count; } else { // // Set the count for Group-and-Source-Specific Query retransmission // set<IPvX>::const_iterator ipvx_iter; for (ipvx_iter = sources.begin(); ipvx_iter != sources.end(); ++ipvx_iter) { const IPvX& ipvx = *ipvx_iter; Mld6igmpSourceRecord* source_record = find_do_forward_source(ipvx); if (source_record == NULL) continue; source_record->set_query_retransmission_count(count); } } // // Set the periodic timer for SSM Group-Specific and // Group-and-Source-Specific Queries. // // Note that we set the timer only if it wasn't running already. // if (! _group_query_timer.scheduled()) { _group_query_timer = eventloop().new_periodic( _mld6igmp_vif.query_last_member_interval().get(), callback(this, &Mld6igmpGroupRecord::group_query_periodic_timeout)); }}/** * Periodic timeout: time to send the next Group-Specific and * Group-and-Source-Specific Queries. * * @return true if the timer should be scheduled again, otherwise false. */boolMld6igmpGroupRecord::group_query_periodic_timeout(){ string dummy_error_msg; bool s_flag = false; set<IPvX> no_sources; // XXX: empty set set<IPvX> sources_with_s_flag; set<IPvX> sources_without_s_flag; Mld6igmpSourceSet::iterator source_iter; TimeVal max_resp_time = mld6igmp_vif().query_last_member_interval().get(); bool do_send_group_query = true; // // XXX: Don't send Group-Specific or Group-and-Source-Specific Queries // for entries that are in IGMPv1 mode. // if (is_igmpv1_mode()) return (false); // // XXX: The IGMPv3/MLDv2 spec doesn't say what to do here if we changed // from a Querier to a non-Querier. // However, the IGMPv2 spec says that Querier to non-Querier transitions // are to be ignored (see the bottom part of Section 3 of RFC 2236). // Hence, for this reason and for robustness purpose we send the Query // messages without taking into account any Querier to non-Querier // transitions. // // // Send the Group-Specific Query message // if (_query_retransmission_count == 0) { do_send_group_query = false; // No more queries to send } else { _query_retransmission_count--; // // Calculate the group-specific "Suppress Router-Side Processing" bit // TimeVal timeval_remaining; group_timer().time_remaining(timeval_remaining); if (timeval_remaining > _mld6igmp_vif.last_member_query_time()) s_flag = true; _mld6igmp_vif.mld6igmp_query_send(mld6igmp_vif().primary_addr(), group(), max_resp_time, group(), no_sources, s_flag, dummy_error_msg); } // // Select all the sources that should be queried, and add them to // the appropriate set. // for (source_iter = _do_forward_sources.begin(); source_iter != _do_forward_sources.end(); ++source_iter) { Mld6igmpSourceRecord* source_record = source_iter->second; size_t count = source_record->query_retransmission_count(); bool s_flag = false; if (count == 0) continue; source_record->set_query_retransmission_count(count - 1); // // Calculate the "Suppress Router-Side Processing" bit // TimeVal timeval_remaining; source_record->source_timer().time_remaining(timeval_remaining); if (timeval_remaining > _mld6igmp_vif.last_member_query_time()) s_flag = true; if (s_flag) sources_with_s_flag.insert(source_record->source()); else sources_without_s_flag.insert(source_record->source()); } // // Send the Group-and-Source-Specific Query messages // if ((! sources_with_s_flag.empty()) && (! do_send_group_query)) { // // According to RFC 3376, Section 6.6.3.2: // "If a group specific query is scheduled to be transmitted at the // same time as a group and source specific query for the same group, // then transmission of the group and source specific message with the // "Suppress Router-Side Processing" bit set may be suppressed." // // The corresponding text from RFC 3810, Section 7.6.3.2 is similar. // _mld6igmp_vif.mld6igmp_query_send(mld6igmp_vif().primary_addr(), group(), max_resp_time, group(), sources_with_s_flag, true, // XXX: set the s_flag dummy_error_msg); } if (! sources_without_s_flag.empty()) { _mld6igmp_vif.mld6igmp_query_send(mld6igmp_vif().primary_addr(), group(), max_resp_time, group(), sources_without_s_flag, false, // XXX: reset the s_flag dummy_error_msg); } if (sources_with_s_flag.empty() && sources_without_s_flag.empty() && (! do_send_group_query)) { return (false); // No more queries to send } return (true); // Schedule the next timeout}/** * Record that an older Membership report message has been received. * * @param message_version the corresponding protocol version of the * received message. */voidMld6igmpGroupRecord::received_older_membership_report(int message_version){ TimeVal timeval = _mld6igmp_vif.older_version_host_present_interval(); if (_mld6igmp_vif.proto_is_igmp()) { switch (message_version) { case IGMP_V1: if (_mld6igmp_vif.is_igmpv2_mode()) { // // XXX: The value specified in RFC 2236 is different from // the value specified in RFC 3376. // timeval = _mld6igmp_vif.group_membership_interval(); } _igmpv1_host_present_timer = eventloop().new_oneoff_after( timeval, callback(this, &Mld6igmpGroupRecord::older_version_host_present_timer_timeout)); break; case IGMP_V2: _igmpv2_mldv1_host_present_timer = eventloop().new_oneoff_after( timeval, callback(this, &Mld6igmpGroupRecord::older_version_host_present_timer_timeout)); break; default: break; } } if (_mld6igmp_vif.proto_is_mld6()) { switch (message_version) { case MLD_V1: _igmpv2_mldv1_host_present_timer = eventloop().new_oneoff_after( timeval, callback(this, &Mld6igmpGroupRecord::older_version_host_present_timer_timeout)); break; default: break; } }}voidMld6igmpGroupRecord::older_version_host_present_timer_timeout(){ // XXX: nothing to do}/** * Test if the group is running in IGMPv1 mode. * * @return true if the group is running in IGMPv1 mode, otherwise false. */boolMld6igmpGroupRecord::is_igmpv1_mode() const{ if (! _mld6igmp_vif.proto_is_igmp()) return (false); if (_mld6igmp_vif.is_igmpv1_mode()) return (true); // XXX: explicitly configured in IGMPv1 mode return (_igmpv1_host_present_timer.scheduled());}/** * Test if the group is running in IGMPv2 mode. * * @return true if the group is running in IGMPv2 mode, otherwise false. */boolMld6igmpGroupRecord::is_igmpv2_mode() const{ if (! _mld6igmp_vif.proto_is_igmp()) return (false); if (is_igmpv1_mode()) return (false); return (_igmpv2_mldv1_host_present_timer.scheduled());}/** * Test if the group is running in IGMPv3 mode. * * @return true if the group is running in IGMPv3 mode, otherwise false. */boolMld6igmpGroupRecord::is_igmpv3_mode() const{ if (! _mld6igmp_vif.proto_is_igmp()) return (false); if (is_igmpv1_mode() || is_igmpv2_mode()) return (false); return (true);}/** * Test if the group is running in MLDv1 mode. * * @return true if the group is running in MLDv1 mode, otherwise false. */boolMld6igmpGroupRecord::is_mldv1_mode() const{ if (! _mld6igmp_vif.proto_is_mld6()) return (false); if (_mld6igmp_vif.is_mldv1_mode()) return (true); // XXX: explicitly configured in MLDv1 mode return (_igmpv2_mldv1_host_present_timer.scheduled());}/** * Test if the group is running in MLDv2 mode. * * @return true if the group is running in MLDv2 mode, otherwise false. */boolMld6igmpGroupRecord::is_mldv2_mode() const{ if (! _mld6igmp_vif.proto_is_mld6()) return (false); if (is_mldv1_mode()) return (false); return (true);}/** * Calculate the forwarding changes and notify the interested parties. * * @param old_is_include mode if true, the old filter mode was INCLUDE, * otherwise was EXCLUDE. * @param old_do_forward_sources the old set of sources to forward. * @param old_dont_forward_sources the old set of sources not to forward. */voidMld6igmpGroupRecord::calculate_forwarding_changes( bool old_is_include_mode, const set<IPvX>& old_do_forward_sources) const{ bool new_is_include_mode = is_include_mode(); set<IPvX> new_do_forward_sources = _do_forward_sources.extract_source_addresses();
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -