⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 mld6igmp_proto.cc

📁 MLDv2 support igmpv3 lite
💻 CC
📖 第 1 页 / 共 2 页
字号:
// -*- c-basic-offset: 4; tab-width: 8; indent-tabs-mode: t -*-// Copyright (c) 2001-2008 XORP, Inc.//// Permission is hereby granted, free of charge, to any person obtaining a// copy of this software and associated documentation files (the "Software")// to deal in the Software without restriction, subject to the conditions// listed in the XORP LICENSE file. These conditions include: you must// preserve this copyright notice, and you cannot mention the copyright// holders in advertising related to the Software without their permission.// The Software is provided WITHOUT ANY WARRANTY, EXPRESS OR IMPLIED. This// notice is a summary of the XORP LICENSE file; the license in that file is// legally binding.#ident "$XORP: xorp/contrib/mld6igmp_lite/mld6igmp_proto.cc,v 1.3 2008/07/23 05:09:49 pavlin Exp $"//// Internet Group Management Protocol implementation.// IGMPv1, IGMPv2 (RFC 2236), and IGMPv3 (RFC 3376).//// AND//// Multicast Listener Discovery protocol implementation.// MLDv1 (RFC 2710) and MLDv2 (RFC 3810).//#include "mld6igmp_module.h"#include "libxorp/xorp.h"#include "libxorp/xlog.h"#include "libxorp/debug.h"#include "libxorp/ipvx.hh"#include <set>#include "mld6igmp_vif.hh"//// Exported variables////// Local constants definitions////// Local structures/classes, typedefs and macros////// Local variables////// Local functions prototypes///** * Mld6igmpVif::mld6igmp_membership_query_recv: * @src: The message source address. * @dst: The message destination address. * @message_type: The message type. * @max_resp_code: The Maximum Response Code from the MLD/IGMP header. * @group_address: The Group Address from the MLD/IGMP message. * @buffer: The buffer with the rest of the message. *  * Receive and process IGMP_MEMBERSHIP_QUERY/MLD_LISTENER_QUERY message * from another router. *  * Return value: %XORP_OK on success, otherwise %XORP_ERROR. **/intMld6igmpVif::mld6igmp_membership_query_recv(const IPvX& src,					    const IPvX& dst,					    uint8_t message_type,					    uint16_t max_resp_code,					    const IPvX& group_address,					    buffer_t *buffer){    int message_version = 0;    // Ignore my own queries    if (mld6igmp_node().is_my_addr(src))	return (XORP_ERROR);    //    // Determine the protocol version of the Query message    //    if (proto_is_igmp()) {	//	// The IGMP version of a Membership Query message is:	// - IGMPv1 Query: length = 8 AND Max Resp Code field is zero	// - IGMPv2 Query: length = 8 AND Max Resp Code field is non-zero	// - IGMPv3 Query: length >= 12	//	do {	    //	    // Note that the Query processing so far has decoded the message	    // up to the group address included (i.e., 8 octets), hence	    // we add-back the size of the decoded portion.	    //	    size_t data_size = BUFFER_DATA_SIZE(buffer) + IGMP_MINLEN;	    if ((data_size == IGMP_MINLEN) && (max_resp_code == 0)) {		message_version = IGMP_V1;		break;	    }	    if ((data_size == IGMP_MINLEN) && (max_resp_code != 0)) {		message_version = IGMP_V2;		break;	    }	    if (data_size >= IGMP_V3_QUERY_MINLEN) {		message_version = IGMP_V3;		break;	    }	    //	    // Silently ignore all other Query messages that don't match	    // any of the above conditions.	    //	    return (XORP_ERROR);	} while (false);	XLOG_ASSERT(message_version > 0);	//	// Query version consistency check.	// If there is mismatch, then drop the message.	// See RFC 3376 Section 7.3.1, and RFC 3810 Section 8.3.1.	//	if (mld6igmp_query_version_consistency_check(src, dst, message_type,						     message_version)	    != XORP_OK) {	    return (XORP_ERROR);	}    }    if (proto_is_mld6()) {	//	// The MLD version of a Membership Query message is:	// - MLDv1 Query: length = 24	// - MLDv2 Query: length >= 28	//	do {	    //	    // Note that the Query processing so far has decoded the message	    // up to the group address included (i.e., 24 octets), hence	    // we add-back the size of the decoded portion.	    //	    size_t data_size = BUFFER_DATA_SIZE(buffer) + MLD_MINLEN;	    if (data_size == MLD_MINLEN) {		message_version = MLD_V1;		break;	    }	    if (data_size >= MLD_V2_QUERY_MINLEN) {		message_version = MLD_V2;		break;	    }	    //	    // Silently ignore all other Query messages that don't match	    // any of the above conditions.	    //	    return (XORP_ERROR);	} while (false);	XLOG_ASSERT(message_version > 0);	//	// Query version consistency check.	// If there is mismatch, then drop the message.	// See RFC 3376 Section 7.3.1, and RFC 3810 Section 8.3.1.	//	if (mld6igmp_query_version_consistency_check(src, dst, message_type,						     message_version)	    != XORP_OK) {	    return (XORP_ERROR);	}    }    XLOG_ASSERT(message_version > 0);        //    // Compare this querier address with my address.    // XXX: Here we should compare the old and new querier    // addresses, but we don't really care.    //    XLOG_ASSERT(primary_addr() != IPvX::ZERO(family()));    if (src < primary_addr()) {	// Eventually a new querier	_query_timer.unschedule();	set_querier_addr(src);	set_i_am_querier(false);	TimeVal other_querier_present_interval =	    effective_query_interval() * effective_robustness_variable()	    + query_response_interval().get() / 2;	_other_querier_timer =	    mld6igmp_node().eventloop().new_oneoff_after(		other_querier_present_interval,		callback(this, &Mld6igmpVif::other_querier_timer_timeout));    }    //    // XXX: if this is IGMPv3 or MLDv2 Query, then process separately    // the rest the message.    //    if ((proto_is_igmp() && (message_version >= IGMP_V3))	|| (proto_is_mld6() && (message_version >= MLD_V2))) {	mld6igmp_ssm_membership_query_recv(src, dst, message_type,					   max_resp_code, group_address,					   buffer);	return (XORP_OK);    }    //    // From RFC 2236:    // "When a non-Querier receives a Group-Specific Query message, if its    // existing group membership timer is greater than [Last Member Query    // Count] times the Max Response Time specified in the message, it sets    // its group membership timer to that value."    //    //    // From RFC 2710:    // "When a router in Non-Querier state receives a Multicast-Address-    // Specific Query, if its timer value for the identified multicast    // address is greater than [Last Listener Query Count] times the Maximum    // Response Delay specified in the message, it sets the address's timer    // to that latter value."    //    if ( (! group_address.is_zero())	 && (max_resp_code != 0)	 && (! i_am_querier())) {	    uint32_t timer_scale = mld6igmp_constant_timer_scale();	    TimeVal received_resp_tv;	    // "Last Member Query Count" / "Last Listener Query Count"	    received_resp_tv = TimeVal(effective_robustness_variable() * max_resp_code, 0);	    received_resp_tv = received_resp_tv / timer_scale;	    _group_records.lower_group_timer(group_address, received_resp_tv);    }    return (XORP_OK);}/** * Mld6igmpVif::mld6igmp_ssm_membership_query_recv: * @src: The message source address. * @dst: The message destination address. * @message_type: The message type. * @max_resp_code: The Maximum Response Code from the MLD/IGMP header. * @group_address: The Group Address from the MLD/IGMP message. * @buffer: The buffer with the rest of the message. *  * Receive and process IGMPv3/MLDv2 IGMP_MEMBERSHIP_QUERY/MLD_LISTENER_QUERY * message from another router. *  * Return value: %XORP_OK on success, otherwise %XORP_ERROR. **/intMld6igmpVif::mld6igmp_ssm_membership_query_recv(const IPvX& src,						const IPvX& dst,						uint8_t message_type,						uint16_t max_resp_code,						const IPvX& group_address,						buffer_t *buffer){    bool s_flag = false;    uint8_t qrv = 0;    uint8_t qqic = 0;    uint16_t sources_n = 0;    TimeVal max_resp_time, qqi;    set<IPvX> sources;    string error_msg;    //    // Decode the Max Resp Code    //    if (proto_is_igmp()) {	decode_exp_time_code8(max_resp_code, max_resp_time,			      mld6igmp_constant_timer_scale());    }    if (proto_is_mld6()) {	decode_exp_time_code16(max_resp_code, max_resp_time,			       mld6igmp_constant_timer_scale());    }    //    // Decode the rest of the message header    //    BUFFER_GET_OCTET(qrv, buffer);    BUFFER_GET_OCTET(qqic, buffer);    BUFFER_GET_HOST_16(sources_n, buffer);    if (proto_is_igmp()) {	s_flag = IGMP_SFLAG(qrv);	qrv = IGMP_QRV(qrv);    }    if (proto_is_mld6()) {	s_flag = MLD_SFLAG(qrv);	qrv = MLD_QRV(qrv);    }    decode_exp_time_code8(qqic, qqi, 1);    //    // Check the remaining size of the message    //    if (BUFFER_DATA_SIZE(buffer) < sources_n * IPvX::addr_bytelen(family())) {	error_msg = c_format("RX %s from %s to %s on vif %s: "			     "source addresses array size too short"			     "(received %u expected at least %u)",			     proto_message_type2ascii(message_type),			     cstring(src), cstring(dst),			     name().c_str(),			     XORP_UINT_CAST(BUFFER_DATA_SIZE(buffer)),			     XORP_UINT_CAST(sources_n * IPvX::addr_bytelen(family())));	XLOG_WARNING("%s", error_msg.c_str());	return (XORP_ERROR);    }    //    // Decode the array of source addresses    //    while (sources_n != 0) {	IPvX ipvx(family());	BUFFER_GET_IPVX(family(), ipvx, buffer);	sources.insert(ipvx);	sources_n--;    }    //    // Adopt the Querier's Robustness Variable and Query Interval    //    if (! i_am_querier()) {	if (qrv != 0) {	    set_effective_robustness_variable(qrv);	} else {	    set_effective_robustness_variable(configured_robust_count().get());	}	if (qqi != TimeVal::ZERO()) {	    set_effective_query_interval(qqi);	} else {	    set_effective_query_interval(configured_query_interval().get());	}    }    //    // Lower the group and source timers    //    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());	}    }    return (XORP_OK); rcvlen_error:    XLOG_UNREACHABLE();    error_msg = c_format("RX %s from %s to %s on vif %s: "			 "some fields are too short",			 proto_message_type2ascii(message_type),			 cstring(src), cstring(dst),			 name().c_str());    XLOG_WARNING("%s", error_msg.c_str());    return (XORP_ERROR);}/** * Mld6igmpVif::mld6igmp_membership_report_recv: * @src: The message source address. * @dst: The message destination address. * @message_type: The message type. * @max_resp_code: The Maximum Response Code from the MLD/IGMP header. * @group_address: The Group Address from the MLD/IGMP message. * @buffer: The buffer with the rest of the message. *  * Receive and process * (IGMP_V1_MEMBERSHIP_REPORT or IGMP_V2_MEMBERSHIP_REPORT)/MLD_LISTENER_REPORT * message from a host. *  * Return value: %XORP_OK on success, otherwise %XORP_ERROR. **/intMld6igmpVif::mld6igmp_membership_report_recv(const IPvX& src,					     const IPvX& dst,					     uint8_t message_type,					     uint16_t max_resp_code,					     const IPvX& group_address,					     buffer_t *buffer){    Mld6igmpGroupRecord *group_record = NULL;        // The group address must be a valid multicast address    if (! group_address.is_multicast()) {	XLOG_WARNING("RX %s from %s to %s on vif %s: "		     "the group address %s is not "		     "valid multicast address",		     proto_message_type2ascii(message_type),		     cstring(src), cstring(dst),		     name().c_str(),		     cstring(group_address));	return (XORP_ERROR);    }    set<IPvX> no_sources;		// XXX: empty set    group_records().process_mode_is_exclude(group_address, no_sources, src);    //    // Check whether an older Membership report has been received    //    int message_version = 0;    if (proto_is_igmp()) {	switch (message_type) {	case IGMP_V1_MEMBERSHIP_REPORT:	    message_version = IGMP_V1;	    break;	case IGMP_V2_MEMBERSHIP_REPORT:	    message_version = IGMP_V2;	    break;	case IGMP_V3_MEMBERSHIP_REPORT:	    message_version = IGMP_V3;	    break;	default:	    message_version = IGMP_V2;	    break;	}    }    if (proto_is_mld6()) {	switch (message_type) {	case MLD_LISTENER_REPORT:	    message_version = MLD_V1;	    break;	case MLDV2_LISTENER_REPORT:	    message_version = MLD_V2;	    break;	default:	    message_version = MLD_V1;	    break;	}    }    XLOG_ASSERT(message_version > 0);    group_record = _group_records.find_group_record(group_address);    XLOG_ASSERT(group_record != NULL);    group_record->received_older_membership_report(message_version);    UNUSED(max_resp_code);    UNUSED(buffer);    return (XORP_OK);}/** * Mld6igmpVif::mld6igmp_leave_group_recv: * @src: The message source address. * @dst: The message destination address. * @message_type: The message type. * @max_resp_code: The Maximum Response Code from the MLD/IGMP header. * @group_address: The Group Address from the MLD/IGMP message. * @buffer: The buffer with the rest of the message. *  * Receive and process IGMP_V2_LEAVE_GROUP/MLD_LISTENER_DONE message * from a host. *  * Return value: %XORP_OK on success, otherwise %XORP_ERROR. **/intMld6igmpVif::mld6igmp_leave_group_recv(const IPvX& src,				       const IPvX& dst,				       uint8_t message_type,				       uint16_t max_resp_code,				       const IPvX& group_address,				       buffer_t *buffer){    Mld6igmpGroupRecord *group_record = NULL;    string dummy_error_msg;    // The group address must be a valid multicast address    if (! group_address.is_multicast()) {	XLOG_WARNING("RX %s from %s to %s on vif %s: "		     "the group address %s is not "		     "valid multicast address",		     proto_message_type2ascii(message_type),		     cstring(src), cstring(dst),		     name().c_str(),		     cstring(group_address));	return (XORP_ERROR);    }    //    // Find if we already have an entry for this group    //    group_record = _group_records.find_group_record(group_address);    if (group_record == NULL) {	// Nothing found. Ignore.	return (XORP_OK);    }    //    // Group found    //    if (is_igmpv1_mode(group_record)) {	//	// Ignore this 'Leave Group' message because this	// group has IGMPv1 hosts members.	//	return (XORP_OK);    }    set<IPvX> no_sources;		// XXX: empty set    group_records().process_change_to_include_mode(group_address, no_sources,						   src);    return (XORP_OK);    UNUSED(max_resp_code);    UNUSED(buffer);        return (XORP_OK);}/** * Mld6igmpVif::mld6igmp_ssm_membership_report_recv: * @src: The message source address. * @dst: The message destination address. * @message_type: The message type. * @buffer: The buffer with the rest of the message. *  * Receive and process IGMP_V3_MEMBERSHIP_REPORT/MLDV2_LISTENER_REPORT * message from a host. *  * Return value: %XORP_OK on success, otherwise %XORP_ERROR. **/int

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -