📄 mld6igmp_vif.cc
字号:
bool ip_internet_control = true; // XXX: always true if (! (is_up() || is_pending_down())) { error_msg = c_format("vif %s is not UP", name().c_str()); return (XORP_ERROR); } XLOG_ASSERT(src != IPvX::ZERO(family())); // // Prepare the MLD or IGMP header. // // Point the buffer to the protocol header datalen = BUFFER_DATA_SIZE(buffer); if (datalen > 0) { BUFFER_RESET_TAIL(buffer); } if (proto_is_igmp()) { BUFFER_PUT_OCTET(message_type, buffer); // The message type BUFFER_PUT_OCTET(max_resp_code, buffer); BUFFER_PUT_HOST_16(0, buffer); // Zero the checksum field BUFFER_PUT_IPVX(group_address, buffer); } if (proto_is_mld6()) { BUFFER_PUT_OCTET(message_type, buffer); // The message type BUFFER_PUT_OCTET(0, buffer); // XXX: Always 0 for MLD BUFFER_PUT_HOST_16(0, buffer); // Zero the checksum field BUFFER_PUT_HOST_16(max_resp_code, buffer); BUFFER_PUT_HOST_16(0, buffer); // Reserved BUFFER_PUT_IPVX(group_address, buffer); } // Restore the buffer to include the data if (datalen > 0) { BUFFER_RESET_TAIL(buffer); BUFFER_PUT_SKIP(datalen, buffer); } // // Compute the checksum // cksum = inet_checksum(BUFFER_DATA_HEAD(buffer), BUFFER_DATA_SIZE(buffer));#ifdef HAVE_IPV6 // Add the checksum for the IPv6 pseudo-header if (proto_is_mld6()) { uint16_t cksum2; size_t ph_len = BUFFER_DATA_SIZE(buffer); cksum2 = calculate_ipv6_pseudo_header_checksum(src, dst, ph_len, IPPROTO_ICMPV6); cksum = inet_checksum_add(cksum, cksum2); }#endif // HAVE_IPV6 BUFFER_COPYPUT_INET_CKSUM(cksum, buffer, 2); // XXX: the checksum XLOG_TRACE(mld6igmp_node().is_log_trace(), "TX %s from %s to %s", proto_message_type2ascii(message_type), cstring(src), cstring(dst)); // // Send the message // ret_value = mld6igmp_node().mld6igmp_send(name(), name(), src, dst, mld6igmp_node().ip_protocol_number(), MINTTL, -1, ip_router_alert, ip_internet_control, buffer, error_msg); return (ret_value); buflen_error: XLOG_UNREACHABLE(); error_msg = c_format("TX %s from %s to %s: " "packet cannot fit into sending buffer", proto_message_type2ascii(message_type), cstring(src), cstring(dst)); XLOG_ERROR("%s", error_msg.c_str()); return (XORP_ERROR);}/** * Send Group-Specific Query message. * * @param group_address the "Multicast Address" or "Group Address" field * in the MLD or IGMP headers respectively. * @param error_msg the error message (if error). * @return XORP_OK on success, otherwise XORP_ERROR. **/intMld6igmpVif::mld6igmp_group_query_send(const IPvX& group_address, string& error_msg){ const IPvX& src = primary_addr(); const IPvX& dst = group_address; const TimeVal& max_resp_time = query_last_member_interval().get(); Mld6igmpGroupRecord* group_record = NULL; set<IPvX> no_sources; // XXX: empty set int ret_value; // // Only the Querier should originate Query messages // if (! i_am_querier()) return (XORP_OK); // Find the group record group_record = _group_records.find_group_record(group_address); if (group_record == NULL) return (XORP_ERROR); // No such group // // Lower the group timer // _group_records.lower_group_timer(group_address, last_member_query_time()); // // Send the message // ret_value = mld6igmp_query_send(src, dst, max_resp_time, group_address, no_sources, false, // XXX: reset the s_flag error_msg); // // Schedule the periodic Group-Specific Query // if (ret_value == XORP_OK) group_record->schedule_periodic_group_query(no_sources); // // Print the error message if there was an error // if (ret_value != XORP_OK) { XLOG_ERROR("Error sending Group-Specific query for %s: %s", cstring(group_address), error_msg.c_str()); } return (ret_value);}/** * Send MLDv2 or IGMPv3 Group-and-Source-Specific Query message. * * @param group_address the "Multicast Address" or "Group Address" field * in the MLD or IGMP headers respectively. * @param sources the set of source addresses. * @param error_msg the error message (if error). * @return XORP_OK on success, otherwise XORP_ERROR. **/intMld6igmpVif::mld6igmp_group_source_query_send(const IPvX& group_address, const set<IPvX>& sources, string& error_msg){ const IPvX& src = primary_addr(); const IPvX& dst = group_address; const TimeVal& max_resp_time = query_last_member_interval().get(); Mld6igmpGroupRecord* group_record = NULL; set<IPvX> selected_sources; set<IPvX>::const_iterator source_iter; int ret_value; // // Only the Querier should originate Query messages // if (! i_am_querier()) return (XORP_OK); if (sources.empty()) return (XORP_OK); // No sources to query // Find the group record group_record = _group_records.find_group_record(group_address); if (group_record == NULL) return (XORP_ERROR); // No such group // // Select only the sources with source timer larger than the // Last Member Query Time. // for (source_iter = sources.begin(); source_iter != sources.end(); ++source_iter) { const IPvX& ipvx = *source_iter; Mld6igmpSourceRecord* source_record; source_record = group_record->find_do_forward_source(ipvx); if (source_record == NULL) continue; TimeVal timeval_remaining; source_record->source_timer().time_remaining(timeval_remaining); if (timeval_remaining <= last_member_query_time()) continue; selected_sources.insert(ipvx); } if (selected_sources.empty()) return (XORP_OK); // No selected sources to query // // Lower the source timer // group_record->lower_source_timer(selected_sources, last_member_query_time()); // // Send the message // ret_value = mld6igmp_query_send(src, dst, max_resp_time, group_address, selected_sources, false, // XXX: reset the s_flag error_msg); // // Schedule the periodic Group-and-Source-Specific Query // if (ret_value == XORP_OK) group_record->schedule_periodic_group_query(selected_sources); // // Print the error message if there was an error // if (ret_value != XORP_OK) { XLOG_ERROR("Error sending Group-and-Source-Specific query for %s: %s", cstring(group_address), error_msg.c_str()); } return (ret_value);}/** * Send MLD or IGMP Query message. * * @param src the message source address. * @param dst the message destination address. * @param max_resp_time the maximum response time. * @param group_address the "Multicast Address" or "Group Address" field * in the MLD or IGMP headers respectively. * @param sources the set of source addresses (for IGMPv3 or MLDv2 only). * @param s_flag the "Suppress Router-Side Processing" bit (for IGMPv3 * or MLDv2 only; in all other cases it should be set to false). * @param error_msg the error message (if error). * @return XORP_OK on success, otherwise XORP_ERROR. **/intMld6igmpVif::mld6igmp_query_send(const IPvX& src, const IPvX& dst, const TimeVal& max_resp_time, const IPvX& group_address, const set<IPvX>& sources, bool s_flag, string& error_msg){ buffer_t *buffer; uint32_t timer_scale = mld6igmp_constant_timer_scale(); TimeVal scaled_max_resp_time = max_resp_time * timer_scale; set<IPvX>::const_iterator source_iter; uint8_t qrv, qqic; size_t max_sources_n; size_t max_payload = 0; Mld6igmpGroupRecord* group_record = NULL; // // Only the Querier should originate Query messages // if (! i_am_querier()) return (XORP_OK); // Find the group record group_record = _group_records.find_group_record(group_address); // // Check protocol version and Query message matching // do { if (sources.empty()) break; // IGMPv3/MLDv2 Query(G, A) message if (is_igmpv3_mode(group_record) || is_mldv2_mode(group_record)) break; // XXX: Query(G, A) messages are not allowed in this mode return (XORP_ERROR); } while (false); // // Lower the group and source timers (if necessary) // if (! s_flag) { if (sources.empty()) { // XXX: Q(G) Query _group_records.lower_group_timer(group_address, last_member_query_time()); } else { // XXX: Q(G, A) Query _group_records.lower_source_timer(group_address, sources, last_member_query_time()); } } // // Prepare the data after the Query header // // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ // | Resv |S| QRV | QQIC | Number of Sources (N) | // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ // qrv = 0; if (effective_robustness_variable() <= 0x7) qrv = effective_robustness_variable(); if (s_flag) qrv |= 0x8; qqic = 0; encode_exp_time_code8(effective_query_interval(), qqic, 1); // // Calculate the maximum number of sources // max_sources_n = sources.size(); if (proto_is_igmp()) { max_payload = mtu() // The MTU of the vif - (0xf << 2) // IPv4 max header size - 4 // IPv4 Router Alert option - IGMP_V3_QUERY_MINLEN; // IGMPv3 Query pre-source fields } if (proto_is_mld6()) { max_payload = mtu() // The MTU of the vif - 8 // IPv6 Hop-by-hop Ext. Header with Router Alert option - MLD_V2_QUERY_MINLEN; // MLDv2 Query pre-source fields } max_sources_n = min(max_sources_n, max_payload / IPvX::addr_bytelen(family())); // // XXX: According to RFC 3810 (MLDv2), Section 8.3.2, the Querier // continues to send MLDv2 queries, regardless of its Multicast Address // Compatibility Mode. // // Interestingly, RFC 3376 (IGMPv3) does not include this statement. // According to the following email, the need for this statement has been // discovered too late to be included in RFC 3376: // http://www1.ietf.org/mail-archive/web/ssm/current/msg00084.html // // // Prepare the buffer // buffer = buffer_send_prepare(); BUFFER_PUT_SKIP(mld6igmp_constant_minlen(), buffer); // // Insert the data (for IGMPv3 and MLDv2 only) // if (is_igmpv3_mode() || is_mldv2_mode()) { // // XXX: Note that we consider only the interface mode, but ignore // the Multicast Address Compatibility Mode. // BUFFER_PUT_OCTET(qrv, buffer); BUFFER_PUT_OCTET(qqic, buffer); BUFFER_PUT_HOST_16(max_sources_n, buffer); source_iter = sources.begin(); while (max_sources_n > 0) { const IPvX& ipvx = *source_iter; BUFFER_PUT_IPVX(ipvx, buffer); ++source_iter; max_sources_n--; } } else { // // If IGMPv1 Multicast Address Compatibility Mode, then set the // Max Response Time to zero. // if (is_igmpv1_mode(group_record)) scaled_max_resp_time = TimeVal::ZERO(); } // // Send the message // return (mld6igmp_send(src, dst, mld6igmp_constant_membership_query(), scaled_max_resp_time.sec(), group_address, buffer, error_msg)); buflen_error: XLOG_UNREACHABLE(); XLOG_ERROR("INTERNAL mld6igmp_query_send() ERROR: " "buffer size too small"); return (XORP_ERROR);}/** * Mld6igmpVif::mld6igmp_recv: * @src: The message source address. * @dst: The message destination address. * @ip_ttl: The IP TTL of the message. If it has a negative value, * it should be ignored. * @ip_tos: The IP TOS of the message. If it has a negative value, * it should be ignored. * @ip_router_alert: True if the received IP packet had the Router Alert * IP option set. * @ip_internet_control: If true, then this is IP control traffic. * @buffer: The buffer with the received message. * @error_msg: The error message (if error). * * Receive MLD or IGMP message and pass it for processing. * * Return value: %XORP_OK on success, otherwise %XORP_ERROR. **/intMld6igmpVif::mld6igmp_recv(const IPvX& src, const IPvX& dst, int ip_ttl, int ip_tos, bool ip_router_alert, bool ip_internet_control, buffer_t *buffer, string& error_msg){ int ret_value = XORP_ERROR; if (! is_up()) { error_msg = c_format("vif %s is not UP", name().c_str()); return (XORP_ERROR); } ret_value = mld6igmp_process(src, dst, ip_ttl, ip_tos, ip_router_alert, ip_internet_control, buffer, error_msg); return (ret_value);}/** * Mld6igmpVif::mld6igmp_process: * @src: The message source address. * @dst: The message destination address. * @ip_ttl: The IP TTL of the message. If it has a negative value, * it should be ignored. * @ip_tos: The IP TOS of the message. If it has a negative value, * it should be ignored. * @ip_router_alert: True if the received IP packet had the Router Alert * IP option set. * @ip_internet_control: If true, then this is IP control traffic. * @buffer: The buffer with the message. * @error_msg: The error message (if error). * * Process MLD or IGMP message and pass the control to the type-specific * functions. * * Return value: %XORP_OK on success, otherwise %XORP_ERROR. **/intMld6igmpVif::mld6igmp_process(const IPvX& src, const IPvX& dst, int ip_ttl, int ip_tos, bool ip_router_alert, bool ip_internet_control, buffer_t *buffer, string& error_msg){ uint8_t message_type = 0; uint16_t max_resp_code = 0; IPvX group_address(family()); uint16_t cksum; bool check_router_alert_option = false;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -