?? mld6igmp_vif.cc
字號:
// -*- 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.//// The Lightweight IGMP/MLD modifications to this file are copyrighted by://// Copyright (c) 2008 Huawei Technologies Co. Ltd//#ident "$XORP: xorp/contrib/mld6igmp_lite/mld6igmp_vif.cc,v 1.3 2008/07/23 05:09:49 pavlin Exp $"//// MLD6IGMP virtual interfaces implementation.//#include "mld6igmp_module.h"#include "libxorp/xorp.h"#include "libxorp/xlog.h"#include "libxorp/debug.h"#include "libxorp/ipvx.hh"#include "libproto/checksum.h"#include "mld6igmp_vif.hh"//// Exported variables////// Local constants definitions////// Local structures/classes, typedefs and macros////// Local variables////// Local functions prototypes///** * Mld6igmpVif::Mld6igmpVif: * @mld6igmp_node: The MLD6IGMP node this interface belongs to. * @vif: The generic Vif interface that contains various information. * * MLD6IGMP protocol vif constructor. **/Mld6igmpVif::Mld6igmpVif(Mld6igmpNode& mld6igmp_node, const Vif& vif) : ProtoUnit(mld6igmp_node.family(), mld6igmp_node.module_id()), Vif(vif), _mld6igmp_node(mld6igmp_node), _proto_flags(0), _primary_addr(IPvX::ZERO(mld6igmp_node.family())), _querier_addr(IPvX::ZERO(mld6igmp_node.family())), _startup_query_count(0), _group_records(*this), _ip_router_alert_option_check(false), _configured_query_interval( TimeVal(0, 0), callback(this, &Mld6igmpVif::set_configured_query_interval_cb)), _effective_query_interval(TimeVal(0, 0)), _query_last_member_interval( TimeVal(0, 0), callback(this, &Mld6igmpVif::set_query_last_member_interval_cb)), _query_response_interval( TimeVal(0, 0), callback(this, &Mld6igmpVif::set_query_response_interval_cb)), _configured_robust_count( 0, callback(this, &Mld6igmpVif::set_configured_robust_count_cb)), _effective_robustness_variable(0), _last_member_query_count(0), _group_membership_interval(TimeVal(0, 0)), _last_member_query_time(TimeVal(0, 0)), _older_version_host_present_interval(TimeVal(0, 0)), _dummy_flag(false){ XLOG_ASSERT(proto_is_igmp() || proto_is_mld6()); // // TODO: when more things become classes, most of this init should go away // _buffer_send = BUFFER_MALLOC(BUF_SIZE_DEFAULT); // // Set the protocol version // if (proto_is_igmp()) { set_proto_version_default(IGMP_VERSION_DEFAULT); _configured_query_interval.set(TimeVal(IGMP_QUERY_INTERVAL, 0)); _query_last_member_interval.set( TimeVal(IGMP_LAST_MEMBER_QUERY_INTERVAL, 0)); _query_response_interval.set(TimeVal(IGMP_QUERY_RESPONSE_INTERVAL, 0)); _configured_robust_count.set(IGMP_ROBUSTNESS_VARIABLE); } if (proto_is_mld6()) { set_proto_version_default(MLD_VERSION_DEFAULT); _configured_query_interval.set(TimeVal(MLD_QUERY_INTERVAL, 0)); _query_last_member_interval.set( TimeVal(MLD_LAST_LISTENER_QUERY_INTERVAL, 0)); _query_response_interval.set(TimeVal(MLD_QUERY_RESPONSE_INTERVAL, 0)); _configured_robust_count.set(MLD_ROBUSTNESS_VARIABLE); } set_proto_version(proto_version_default());}/** * Mld6igmpVif::~Mld6igmpVif: * @: * * MLD6IGMP protocol vif destructor. * **/Mld6igmpVif::~Mld6igmpVif(){ string error_msg; stop(error_msg); _group_records.delete_payload_and_clear(); BUFFER_FREE(_buffer_send);}/** * Mld6igmpVif::set_proto_version: * @proto_version: The protocol version to set. * * Set protocol version. * * Return value: %XORP_OK is @proto_version is valid, otherwise %XORP_ERROR. **/intMld6igmpVif::set_proto_version(int proto_version){ if (proto_is_igmp()) { if ((proto_version < IGMP_VERSION_MIN) || (proto_version > IGMP_VERSION_MAX)) { return (XORP_ERROR); } if (proto_version < IGMP_V3) { // // XXX: Restore the variables that might have been adopted from // the Querier. // restore_effective_variables(); } } if (proto_is_mld6()) { if ((proto_version < MLD_VERSION_MIN) || (proto_version > MLD_VERSION_MAX)) { return (XORP_ERROR); } if (proto_version < IGMP_V3) { // // XXX: Restore the variables that might have been adopted from // the Querier. // restore_effective_variables(); } } ProtoUnit::set_proto_version(proto_version); return (XORP_OK);}/** * Mld6igmpVif::proto_is_ssm: * @: * * Test if the interface is running a source-specific multicast capable * protocol version (e.g. IGMPv3 or MLDv2). * * Return value: @true if the protocol version is source-specific multicast * capable, otherwise @fa.se **/boolMld6igmpVif::proto_is_ssm() const{ if (proto_is_igmp()) return (proto_version() >= IGMP_V3); if (proto_is_mld6()) return (proto_version() >= MLD_V2); return (false);}/** * Mld6igmpVif::start: * @error_msg: The error message (if error). * * Start MLD or IGMP on a single virtual interface. * * Return value: %XORP_OK on success, otherwise %XORP_ERROR. **/intMld6igmpVif::start(string& error_msg){ string dummy_error_msg; if (! is_enabled()) return (XORP_OK); if (is_up() || is_pending_up()) return (XORP_OK); if (! is_underlying_vif_up()) { error_msg = "underlying vif is not UP"; return (XORP_ERROR); } // // Start the vif only if it is of the appropriate type: // multicast-capable (loopback excluded). // if (! (is_multicast_capable() && (! is_loopback()))) { error_msg = "the interface is not multicast capable"; return (XORP_ERROR); } if (update_primary_address(error_msg) != XORP_OK) return (XORP_ERROR); if (ProtoUnit::start() != XORP_OK) { error_msg = "internal error"; return (XORP_ERROR); } // On startup, assume I am the MLD6IGMP Querier set_querier_addr(primary_addr()); set_i_am_querier(true); // // Register as a receiver with the kernel // if (mld6igmp_node().register_receiver(name(), name(), mld6igmp_node().ip_protocol_number(), true) != XORP_OK) { error_msg = c_format("cannot register as a receiver on vif %s " "with the kernel", name().c_str()); return (XORP_ERROR); } // // Join the appropriate multicast groups: ALL-SYSTEMS, ALL-ROUTERS, // and SSM-ROUTERS. // list<IPvX> groups; list<IPvX>::iterator groups_iter; groups.push_back(IPvX::MULTICAST_ALL_SYSTEMS(family())); groups.push_back(IPvX::MULTICAST_ALL_ROUTERS(family())); groups.push_back(IPvX::SSM_ROUTERS(family())); for (groups_iter = groups.begin(); groups_iter != groups.end(); ++groups_iter) { const IPvX& group = *groups_iter; if (mld6igmp_node().join_multicast_group(name(), name(), mld6igmp_node().ip_protocol_number(), group) != XORP_OK) { error_msg = c_format("cannot join group %s on vif %s", cstring(group), name().c_str()); return (XORP_ERROR); } } // // Query all members on startup // TimeVal max_resp_time = query_response_interval().get(); set<IPvX> no_sources; // XXX: empty set mld6igmp_query_send(primary_addr(), IPvX::MULTICAST_ALL_SYSTEMS(family()), max_resp_time, IPvX::ZERO(family()), no_sources, false, dummy_error_msg); _startup_query_count = effective_robustness_variable(); if (_startup_query_count > 0) _startup_query_count--; TimeVal startup_query_interval = effective_query_interval() / 4; _query_timer = mld6igmp_node().eventloop().new_oneoff_after( startup_query_interval, callback(this, &Mld6igmpVif::query_timer_timeout)); XLOG_INFO("Interface started: %s%s", this->str().c_str(), flags_string().c_str()); return (XORP_OK);}/** * Mld6igmpVif::stop: * @error_msg: The error message (if error). * * Stop MLD or IGMP on a single virtual interface. * * Return value: %XORP_OK on success, otherwise %XORP_ERROR. **/intMld6igmpVif::stop(string& error_msg){ int ret_value = XORP_OK; if (is_down()) return (XORP_OK); if (! (is_up() || is_pending_up() || is_pending_down())) { error_msg = "the vif state is not UP or PENDING_UP or PENDING_DOWN"; return (XORP_ERROR); } if (ProtoUnit::pending_stop() != XORP_OK) { error_msg = "internal error"; ret_value = XORP_ERROR; } // // XXX: we don't have to explicitly leave the multicast groups // we have joined on that interface, because this will happen // automatically when we stop the vif through the MFEA. // if (ProtoUnit::stop() != XORP_OK) { error_msg = "internal error"; ret_value = XORP_ERROR; } set_i_am_querier(false); set_querier_addr(IPvX::ZERO(family())); // XXX: ANY _other_querier_timer.unschedule(); _query_timer.unschedule(); _startup_query_count = 0; // Notify routing and remove all group records Mld6igmpGroupSet::const_iterator group_iter; for (group_iter = _group_records.begin(); group_iter != _group_records.end(); ++group_iter) { const Mld6igmpGroupRecord *group_record = group_iter->second; Mld6igmpSourceSet::const_iterator source_iter; // Clear the state for all included sources for (source_iter = group_record->do_forward_sources().begin(); source_iter != group_record->do_forward_sources().end(); ++source_iter) { const Mld6igmpSourceRecord *source_record = source_iter->second; join_prune_notify_routing(source_record->source(), group_record->group(), ACTION_PRUNE); } // Clear the state for all excluded sources if (group_record->is_asm_mode()) { join_prune_notify_routing(IPvX::ZERO(family()), group_record->group(), ACTION_PRUNE); } } _group_records.delete_payload_and_clear(); // // Unregister as a receiver with the kernel // if (mld6igmp_node().unregister_receiver(name(), name(), mld6igmp_node().ip_protocol_number()) != XORP_OK) { XLOG_ERROR("Cannot unregister as a receiver on vif %s with the kernel", name().c_str()); ret_value = XORP_ERROR; } XLOG_INFO("Interface stopped: %s%s", this->str().c_str(), flags_string().c_str()); // // Inform the node that the vif has completed the shutdown // mld6igmp_node().vif_shutdown_completed(name()); return (ret_value);}/** * Enable MLD/IGMP on a single virtual interface. * * If an unit is not enabled, it cannot be start, or pending-start. */voidMld6igmpVif::enable(){ ProtoUnit::enable(); XLOG_INFO("Interface enabled: %s%s", this->str().c_str(), flags_string().c_str());}/** * Disable MLD/IGMP on a single virtual interface. * * If an unit is disabled, it cannot be start or pending-start. * If the unit was runnning, it will be stop first. */voidMld6igmpVif::disable(){ string error_msg; stop(error_msg); ProtoUnit::disable(); XLOG_INFO("Interface disabled: %s%s", this->str().c_str(), flags_string().c_str());}/** * Mld6igmpVif::mld6igmp_send: * @src: The message source address. * @dst: The message destination address. * @message_type: The MLD or IGMP type of the message. * @max_resp_code: The "Maximum Response Code" or "Max Resp Code" * field in the MLD or IGMP headers respectively (in the particular * protocol resolution). * @group_address: The "Multicast Address" or "Group Address" field * in the MLD or IGMP headers respectively. * @buffer: The buffer with the rest of the message. * @error_msg: The error message (if error). * * Send MLD or IGMP message. * * Return value: %XORP_OK on success, otherwise %XORP_ERROR. **/intMld6igmpVif::mld6igmp_send(const IPvX& src, const IPvX& dst, uint8_t message_type, uint16_t max_resp_code, const IPvX& group_address, buffer_t *buffer, string& error_msg){ uint16_t cksum; int ret_value; size_t datalen; bool ip_router_alert = true; // XXX: always use Router Alert option
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -