// -*- c-basic-offset: 4; tab-width: 8; indent-tabs-mode: t -*- // Copyright (c) 2001-2009 XORP, Inc. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, Version 2, June // 1991 as published by the Free Software Foundation. Redistribution // and/or modification of this program under the terms of any other // version of the GNU General Public License is not permitted. // // This program is distributed in the hope that it will be useful, but // WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. For more details, // see the GNU General Public License, Version 2, a copy of which can be // found in the XORP LICENSE.gpl file. // // XORP Inc, 2953 Bunker Hill Lane, Suite 204, Santa Clara, CA 95054, USA; // http://xorp.net // $XORP: xorp/pim/pim_bsr.hh,v 1.25 2009/01/05 18:31:02 jtc Exp $ #ifndef __PIM_PIM_BSR_HH__ #define __PIM_PIM_BSR_HH__ // // PIM Bootstrap Router (BSR) mechanism definitions // #include <list> #include "libxorp/ipvx.hh" #include "libxorp/ipvxnet.hh" #include "libxorp/timer.hh" #include "libproto/proto_unit.hh" #include "pim_scope_zone_table.hh" // // Constants definitions // // // Structures/classes, typedefs and macros // class PimNode; class PimVif; class BsrGroupPrefix; class BsrZone; class BsrRp; // The PIM BSR class class PimBsr : public ProtoUnit { public: PimBsr(PimNode& pim_node); virtual ~PimBsr(); /** * Clear the entry. */ void clear(); /** * Start operation. * * @return XORP_OK on success, otherwise XORP_ERROR. */ int start(); /** * Stop operation. * * @return XORP_OK on success, otherwise XORP_ERROR. */ int stop(); /** * Enable operation. * * If an unit is not enabled, it cannot be start, or pending-start. */ void enable(); /** * Disable operation. * * If an unit is disabled, it cannot be start or pending-start. * If the unit was runnning, it will be stop first. */ void disable(); PimNode& pim_node() const { return (_pim_node); } int unicast_pim_bootstrap(PimVif *pim_vif, const IPvX& nbr_addr) const; list<BsrZone *>& config_bsr_zone_list() { return (_config_bsr_zone_list); } list<BsrZone *>& active_bsr_zone_list() { return (_active_bsr_zone_list); } list<BsrZone *>& expire_bsr_zone_list() { return (_expire_bsr_zone_list); } BsrZone *add_config_bsr_zone(const BsrZone& bsr_zone, string& error_msg); BsrZone *add_active_bsr_zone(const BsrZone& bsr_zone, string& error_msg); BsrZone *add_expire_bsr_zone(const BsrZone& bsr_zone); void delete_config_bsr_zone(BsrZone *old_bsr_zone); void delete_active_bsr_zone(BsrZone *old_bsr_zone); void delete_expire_bsr_zone(BsrZone *old_bsr_zone); void delete_all_expire_bsr_zone_by_zone_id(const PimScopeZoneId& zone_id); void delete_expire_bsr_zone_prefix(const IPvXNet& group_prefix, bool is_scope_zone); BsrZone *find_config_bsr_zone(const PimScopeZoneId& zone_id) const; BsrZone *find_active_bsr_zone(const PimScopeZoneId& zone_id) const; BsrZone *find_config_bsr_zone_by_prefix(const IPvXNet& group_prefix, bool is_scope_zone) const; BsrZone *find_active_bsr_zone_by_prefix(const IPvXNet& group_prefix, bool is_scope_zone) const; BsrRp *find_rp(const IPvXNet& group_prefix, bool is_scope_zone, const IPvX& rp_addr) const; void add_rps_to_rp_table(); void schedule_rp_table_apply_rp_changes(); void clean_expire_bsr_zones(); void schedule_clean_expire_bsr_zones(); void add_vif_addr(uint32_t vif_index, const IPvX& vif_addr); void delete_vif_addr(uint32_t vif_index, const IPvX& vif_addr); // // Test-related methods // BsrZone *add_test_bsr_zone(const PimScopeZoneId& zone_id, const IPvX& bsr_addr, uint8_t bsr_priority, uint8_t hash_mask_len, uint16_t fragment_tag); BsrZone *find_test_bsr_zone(const PimScopeZoneId& zone_id) const; BsrGroupPrefix *add_test_bsr_group_prefix(const PimScopeZoneId& zone_id, const IPvXNet& group_prefix, bool is_scope_zone, uint8_t expected_rp_count); BsrRp *add_test_bsr_rp(const PimScopeZoneId& zone_id, const IPvXNet& group_prefix, const IPvX& rp_addr, uint8_t rp_priority, uint16_t rp_holdtime); int send_test_bootstrap(const string& vif_name, string& error_msg); int send_test_bootstrap_by_dest(const string& vif_name, const IPvX& dest_addr, string& error_msg); int send_test_cand_rp_adv(); private: void rp_table_apply_rp_changes_timer_timeout(); void clean_expire_bsr_zones_timer_timeout(); BsrZone *find_bsr_zone_by_prefix_from_list( const list<BsrZone *>& zone_list, const IPvXNet& group_prefix, bool is_scope_zone) const; bool can_add_config_bsr_zone(const BsrZone& bsr_zone, string& error_msg) const; bool can_add_active_bsr_zone(const BsrZone& bsr_zone, string& error_msg) const; PimNode& _pim_node; // The associated PIM node list<BsrZone *> _config_bsr_zone_list; // List of configured Cand-BSR // zones and/or Cand-RP info list<BsrZone *> _active_bsr_zone_list; // List of active BSR zones list<BsrZone *> _expire_bsr_zone_list; // List of expiring BSR zones list<BsrZone *> _test_bsr_zone_list; // List of test BSR zones XorpTimer _rp_table_apply_rp_changes_timer; // Timer to apply RP changes // to the RpTable XorpTimer _clean_expire_bsr_zones_timer; // Timer to cleanup expiring // BSR zones }; class BsrZone { public: BsrZone(PimBsr& pim_bsr, const BsrZone& bsr_zone); BsrZone(PimBsr& pim_bsr, const PimScopeZoneId& zone_id); BsrZone(PimBsr& pim_bsr, const IPvX& bsr_addr, uint8_t bsr_priority, uint8_t hash_mask_len, uint16_t fragment_tag); ~BsrZone(); PimBsr& pim_bsr() { return (_pim_bsr); } // // BsrZone type // bool is_config_bsr_zone() const { return (_is_config_bsr_zone); } bool is_active_bsr_zone() const { return (_is_active_bsr_zone); } bool is_expire_bsr_zone() const { return (_is_expire_bsr_zone); } bool is_test_bsr_zone() const { return (_is_test_bsr_zone); } void set_config_bsr_zone(bool v); void set_active_bsr_zone(bool v); void set_expire_bsr_zone(bool v); void set_test_bsr_zone(bool v); const IPvX& bsr_addr() const { return (_bsr_addr); } void set_bsr_addr(const IPvX& v) { _bsr_addr = v; } uint8_t bsr_priority() const { return (_bsr_priority); } void set_bsr_priority(uint8_t v) { _bsr_priority = v; } uint8_t hash_mask_len() const { return (_hash_mask_len); } uint16_t fragment_tag() const { return (_fragment_tag); } uint16_t new_fragment_tag() { return (++_fragment_tag); } bool is_accepted_message() const { return (_is_accepted_message); } void set_is_accepted_message(bool v) { _is_accepted_message = v; } bool is_unicast_message() const { return (_is_unicast_message); } const IPvX& unicast_message_src() const { return (_unicast_message_src); } void set_is_unicast_message(bool v, const IPvX& src) { _is_unicast_message = v; _unicast_message_src = src; } bool is_cancel() const { return (_is_cancel); } void set_is_cancel(bool v) { _is_cancel = v; } const PimScopeZoneId& zone_id() const { return (_zone_id); } void set_zone_id(const PimScopeZoneId& zone_id) { _zone_id = zone_id; } // The states used per scope zone enum bsr_zone_state_t { STATE_INIT, // The state after initialization // States if I am a Candidate BSR STATE_CANDIDATE_BSR, STATE_PENDING_BSR, STATE_ELECTED_BSR, // States if I am not a Candidate BSR STATE_NO_INFO, STATE_ACCEPT_ANY, STATE_ACCEPT_PREFERRED }; bsr_zone_state_t bsr_zone_state() const { return (_bsr_zone_state); } void set_bsr_zone_state(bsr_zone_state_t v) { _bsr_zone_state = v; } /** * Update the configuration of a BSR zone. * * @param new_bsr_zone the BSR zone with the new configuration. * @param error_msg the error message (if error). * @return XORP_OK on success, otherwise XORP_ERROR. */ int update_config_bsr_zone(const BsrZone& new_bsr_zone, string& error_msg); bool is_consistent(string& error_msg) const; bool can_merge_rp_set(const BsrZone& bsr_zone, string& error_msg) const; void merge_rp_set(const BsrZone& bsr_zone); void store_rp_set(const BsrZone& bsr_zone); XorpTimer& bsr_timer() { return (_bsr_timer); } const XorpTimer& const_bsr_timer() const { return (_bsr_timer); } void expire_bsr_timer(); XorpTimer& scope_zone_expiry_timer() { return (_scope_zone_expiry_timer); } const XorpTimer& const_scope_zone_expiry_timer() const { return (_scope_zone_expiry_timer); } const list<BsrGroupPrefix *>& bsr_group_prefix_list() const { return (_bsr_group_prefix_list); } list<BsrGroupPrefix *>& bsr_group_prefix_list() { return (_bsr_group_prefix_list); } BsrGroupPrefix *add_bsr_group_prefix(const IPvXNet& group_prefix_init, bool is_scope_zone_init, uint8_t expected_rp_count); void delete_bsr_group_prefix(BsrGroupPrefix *bsr_group_prefix); BsrGroupPrefix *find_bsr_group_prefix(const IPvXNet& group_prefix) const; bool process_candidate_bsr(const BsrZone& cand_bsr_zone); bool i_am_bsr() const; bool is_new_bsr_preferred(const BsrZone& bsr_zone) const; bool is_new_bsr_same_priority(const BsrZone& bsr_zone) const; struct TimeVal randomized_override_interval(const IPvX& my_addr, uint8_t my_priority) const; bool is_bsm_forward() const { return (_is_bsm_forward); } void set_bsm_forward(bool v) { _is_bsm_forward = v; } bool is_bsm_originate() const { return (_is_bsm_originate); } void set_bsm_originate(bool v) { _is_bsm_originate = v; } bool i_am_candidate_bsr() const { return (_i_am_candidate_bsr); } void set_i_am_candidate_bsr(bool i_am_candidate_bsr, uint32_t my_vif_index, const IPvX& my_bsr_addr, uint8_t my_bsr_priority); uint32_t my_vif_index() const { return (_my_vif_index); } const IPvX& my_bsr_addr() const { return (_my_bsr_addr); } uint8_t my_bsr_priority() const { return (_my_bsr_priority); } bool is_my_bsr_addr_explicit() const { return (_is_my_bsr_addr_explicit); } void set_is_my_bsr_addr_explicit(bool v) { _is_my_bsr_addr_explicit = v; } // // Cand-RP related methods // BsrRp *find_rp(const IPvXNet& group_prefix, const IPvX& rp_addr) const; BsrRp *add_rp(const IPvXNet& group_prefix, bool is_scope_zone_init, const IPvX& rp_addr, uint8_t rp_priority, uint16_t rp_holdtime, string& error_msg); XorpTimer& candidate_rp_advertise_timer() { return (_candidate_rp_advertise_timer); } const XorpTimer& const_candidate_rp_advertise_timer() const { return (_candidate_rp_advertise_timer); } void start_candidate_rp_advertise_timer(); void expire_candidate_rp_advertise_timer(); private: void bsr_timer_timeout(); void scope_zone_expiry_timer_timeout(); void candidate_rp_advertise_timer_timeout(); PimBsr& _pim_bsr; // The PimBsr for this BsrZone // BsrZone type bool _is_config_bsr_zone; // True if config BSR zone bool _is_active_bsr_zone; // True if active BSR zone bool _is_expire_bsr_zone; // True if expire BSR zone bool _is_test_bsr_zone; // True if test BSR zone // State at all routers IPvX _bsr_addr; // The address of the Bootstrap router uint8_t _bsr_priority; // The BSR priority (larger is better) uint8_t _hash_mask_len; // The hash mask length uint16_t _fragment_tag; // The fragment tag bool _is_accepted_message; // True if info accepted already bool _is_unicast_message; // True if info received by unicast IPvX _unicast_message_src; // The source address of the info // (if received by unicast) PimScopeZoneId _zone_id; // The (prefix-based) scope zone ID. // If non-scoped zone, the ID is // IPvXNet:ip_multicast_base_prefix() XorpTimer _bsr_timer; // The Bootstrap Timer list<BsrGroupPrefix *> _bsr_group_prefix_list; // The list of group // prefixes for this zone. // XXX: if a scope zone, and if there // is a group-RP prefix for the whole // zone, this prefix must be in front. bsr_zone_state_t _bsr_zone_state; // Scope zone state XorpTimer _scope_zone_expiry_timer; // The Scope-Zone Expiry Timer // State at a Candidate BSR bool _i_am_candidate_bsr; // True if I am Cand-BSR for this zone uint32_t _my_vif_index; // The vif index with my address // if a Cand-BSR IPvX _my_bsr_addr; // My address if a Cand-BSR uint8_t _my_bsr_priority; // My BSR priority if a Cand-BSR bool _is_my_bsr_addr_explicit; // True if my Cand-BSR address was // set explicitly // State at a Candidate RP XorpTimer _candidate_rp_advertise_timer; // The C-RP Adv. Timer // Misc. state bool _is_bsm_forward; // Temp. state: if true, forward BSM bool _is_bsm_originate; // Temp. state: if true, originate BSM bool _is_cancel; // True if we are canceling this zone }; class BsrGroupPrefix { public: BsrGroupPrefix(BsrZone& bsr_zone, const IPvXNet& group_prefix, bool is_scope_zone, uint8_t expected_rp_count); BsrGroupPrefix(BsrZone& bsr_zone, const BsrGroupPrefix& bsr_group_prefix); ~BsrGroupPrefix(); BsrZone& bsr_zone() { return (_bsr_zone); } bool is_scope_zone() const { return (_is_scope_zone); } const IPvXNet& group_prefix() const { return (_group_prefix); } uint8_t expected_rp_count() const { return (_expected_rp_count); } uint8_t received_rp_count() const { return (_received_rp_count); } void set_received_rp_count(uint8_t v) { _received_rp_count = v; } void set_expected_rp_count(uint8_t v) { _expected_rp_count = v; } const list<BsrRp *>& rp_list() const { return (_rp_list); } list<BsrRp *>& rp_list() { return (_rp_list); } BsrRp *add_rp(const IPvX& rp_addr, uint8_t rp_priority, uint16_t rp_holdtime); void delete_rp(BsrRp *bsr_rp); BsrRp *find_rp(const IPvX& rp_addr) const; bool is_completed() const { return (_expected_rp_count == _received_rp_count); } // Removal related methods void schedule_bsr_group_prefix_remove(); const XorpTimer& const_remove_timer() const { return (_remove_timer); } private: void remove_timer_timeout(); BsrZone& _bsr_zone; // The BSR zone I belong to // Group prefix state IPvXNet _group_prefix; // The group address prefix bool _is_scope_zone; // True if prefix for admin. scope zone uint8_t _expected_rp_count; // Expected number of RPs uint8_t _received_rp_count; // Received number of RPs so far list<BsrRp *> _rp_list; // The list of received RPs // Misc. state XorpTimer _remove_timer; // Timer to remove empty prefix }; class BsrRp { public: BsrRp(BsrGroupPrefix& bsr_group_prefix, const IPvX& rp_addr, uint8_t rp_priority, uint16_t rp_holdtime); BsrRp(BsrGroupPrefix& bsr_group_prefix, const BsrRp& bsr_rp); BsrGroupPrefix& bsr_group_prefix() { return (_bsr_group_prefix); } const IPvX& rp_addr() const { return (_rp_addr); } void set_rp_addr(const IPvX& v) { _rp_addr = v; } uint8_t rp_priority() const { return (_rp_priority); } uint16_t rp_holdtime() const { return (_rp_holdtime); } void set_rp_priority(uint8_t v) { _rp_priority = v; } void set_rp_holdtime(uint16_t v) { _rp_holdtime = v; } const XorpTimer& const_candidate_rp_expiry_timer() const { return (_candidate_rp_expiry_timer); } void start_candidate_rp_expiry_timer(); uint32_t my_vif_index() const { return (_my_vif_index); } void set_my_vif_index(uint32_t v) { _my_vif_index = v; } bool is_my_rp_addr_explicit() const { return (_is_my_rp_addr_explicit); } void set_is_my_rp_addr_explicit(bool v) { _is_my_rp_addr_explicit = v; } private: void candidate_rp_expiry_timer_timeout(); BsrGroupPrefix& _bsr_group_prefix; // The BSR prefix I belong to // RP state IPvX _rp_addr; // The address of the RP uint8_t _rp_priority; // RP priority (smaller is better) uint16_t _rp_holdtime; // RP holdtime (in seconds) XorpTimer _candidate_rp_expiry_timer; // The C-RP Expiry Timer uint32_t _my_vif_index; // The vif index with my address // if a Cand-RP bool _is_my_rp_addr_explicit; // True if my Cand-RP address was // set explicitly }; // // Global variables // // // Global functions prototypes // #endif // __PIM_PIM_BSR_HH__