Source: ../../ospf/area_router.hh


 
LOGO
 Annotated List  Files  Globals  Hierarchy  Index  Top
// -*- c-basic-offset: 4; tab-width: 8; indent-tabs-mode: t -*-
// vim:set sts=4 ts=8:

// Copyright (c) 2001-2006 International Computer Science Institute
//
// 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.

// $XORP: xorp/ospf/area_router.hh,v 1.102 2006/03/28 03:06:53 atanu Exp $

#ifndef __OSPF_AREA_ROUTER_HH__
#define __OSPF_AREA_ROUTER_HH__

class DataBaseHandle;

/**
 * Area Router
 * 
 */
template <typename A>
class AreaRouter : public ServiceBase {
 public:
    AreaRouter(Ospf<A>& ospf, OspfTypes::AreaID area,
	       OspfTypes::AreaType area_type);

    /**
     * Required by the class Subsystem.
     * Called on startup.
     */
    bool startup();

    /**
     * Required by the class Subsystem.
     * Called on shutdown.
     */
    bool shutdown();

    /**
     * Add peer
     */
    void add_peer(PeerID peer);

    /**
     * Delete peer
     */
    void delete_peer(PeerID peer);

    /**
     * Peer came up
     */
    bool peer_up(PeerID peer);

    /**
     * Peer went down
     */
    bool peer_down(PeerID peer);

    /**
     * Track border router transitions.
     *
     * @param up true of the router just became an area border router,
     * false if the router was an area border router and is no longer.
     */
    void area_border_router_transition(bool up);

    /**
     * Change the type of this area.
     */
    void change_area_router_type(OspfTypes::AreaType area_type);

    /**
     * Add a virtual link endpoint.
     */
    bool add_virtual_link(OspfTypes::RouterID rid);

    /**
     * Remove a virtual link endpoint.
     */
    bool remove_virtual_link(OspfTypes::RouterID rid);

    /**
     * Start looking through the list of routers for a virtual link endpoint.
     */
    void start_virtual_link();

    /**
     * Check this node to see if its a virtual link endpoint.
     *
     * @param rc node under consideration.
     * @param router this router's Router-LSA.
     */
    void check_for_virtual_link(const RouteCmd<Vertex>& rc, Lsa::LsaRef lsar);

    /**
     * End looking through the list of routers for a virtual link endpoint.
     */
    void end_virtual_link();

    /**
     * Given two LSAs find the interface address of the destination
     * LSA. The source LSA can be a Router-LSA or a Network-LSA the
     * destination LSA must be a Router-LSA.
     */
    bool find_interface_address(Lsa::LsaRef src, Lsa::LsaRef dst,
				A& interface)const;

    /**
     * Add area range.
     */
    bool area_range_add(IPNet<A> net, bool advertise);

    /**
     * Delete area range.
     */
    bool area_range_delete(IPNet<A> net);

    /**
     * Change the advertised state of this area.
     */
    bool area_range_change_state(IPNet<A> net, bool advertise);

    /**
     * Is network covered by an area range and if it is should it be
     * advertised.
     */
    bool area_range_covered(IPNet<A> net, bool& advertise);

    /**
     * This network falls in a covered area range, return the covering
     * range.
     */
    bool area_range_covering(IPNet<A> net, IPNet<A>& sumnet);

    /**
     * Does this area have any area ranges configured.
     */
    bool area_range_configured();

    /**
     * If this is a "stub" or "nssa" area toggle the sending of a default
     *  route.
     */
    bool originate_default_route(bool enable);

    /**
     *  Set the StubDefaultCost, the default cost sent in a default route in a
     *  "stub" or "nssa" area.
     */
    bool stub_default_cost(uint32_t cost);

    /**
     *  Toggle the sending of summaries into "stub" or "nssa" areas.
     */
    bool summaries(bool enable);

    /**
     * get lsa at index if it exists.
     */
    bool get_lsa(const uint32_t index, bool& valid, bool& toohigh, bool& self,
		 vector<uint8_t>& lsa);
    
    /**
     * A new set of router links.
     */
    bool new_router_links(PeerID peer, const list<RouterLink>& router_link);

    /**
     * Refresh Router-LSA.
     *
     * Cause the generation of a new Router-LSA if necessary.
     *
     * @param timer true if called by the timer.
     */
    void refresh_router_lsa(bool timer = false);

    /**
     * A new route has been added to the routing table it is being
     * presented to this area for possible Summary-LSA generation.
     *
     * @param area the route came from
     * @param net
     * @param rt routing entry.
     * @param push true if the routes are arriving as a consquence of
     * calling summary_push()
     */
    void summary_announce(OspfTypes::AreaID area, IPNet<A> net,
			  RouteEntry<A>& rt, bool push);

    /**
     * A route has been deleted from the routing table. It may
     * previously have caused a Summary-LSA which now needs to be
     * withdrawn.
     */
    void summary_withdraw(OspfTypes::AreaID area, IPNet<A> net,
			  RouteEntry<A>& rt);

     /**
      * @return true if this area should accept an AS-External-LSA or
      * a Type-7-LSA.
      */
    bool external_area_type() const;
 
    /**
     * Copy the net and nexthop information from one AS-External-LSA to
     * another.
     *
     * The first dummy argument A is to allow template specialisation
     * by address family.
     */
    void external_copy_net_nexthop(A,
				   ASExternalLsa *dst,
				   ASExternalLsa *src);

    /**
     * Given an AS-External-LSA generate a Type-7 LSA.
     *
     * @param indb if true the Type-7-LSA is already in the database.
     */
    Lsa::LsaRef external_generate_type7(Lsa::LsaRef lsar, bool& indb);

    /**
     * Given a Type-7 LSA generate an AS-External-LSA.
     */
    Lsa::LsaRef external_generate_external(Lsa::LsaRef lsar);

    /**
     * An AS-External-LSA being announced either from another area or
     * from the RIB as a redist.
     *
     * The LSAs should not be scheduled for transmission until the
     * external_shove() is seen. In many cases a number of LSAs may
     * arrive in a single packet, waiting for the external_shove()
     * offers an opportunity for aggregation.
     *
     * @param lsar the AS-External-LSA
     * @param push set to true if the push is a result of an external_push().
     * @param redist true if this LSA was locally generated due to a
     * redistribution.
     */
    void external_announce(Lsa::LsaRef lsar, bool push, bool redist);

    /**
     * Called to complete a series of calls to external_announce().
     */
    void external_shove();

    /**
     * Refresh this LSA either because a timer has expired or because
     * a newer LSA has arrived from another area. In either cause the
     * LSA should already be in this area's database.
     */
    void external_refresh(Lsa::LsaRef lsar);

    /**
     * An AS-External-LSA being withdrawn either from another area or
     * from the RIB as a redist.
     *
     * @param lsar the AS-External-LSA
     */
    void external_withdraw(Lsa::LsaRef lsar);

    /**
     * Generate a Network-LSA for this peer.
     */
    bool generate_network_lsa(PeerID peer,
			      OspfTypes::RouterID link_state_id,
			      list<OspfTypes::RouterID>& attached_routers,
			      uint32_t network_mask);

    /**
     * Update the Network-LSA for this peer.
     */
    bool update_network_lsa(PeerID peer,
			    OspfTypes::RouterID link_state_id,
			    list<OspfTypes::RouterID>& attached_routers,
			    uint32_t network_mask);

    /**
     * Withdraw the Network-LSA for this peer by prematurely aging.
     */
    bool withdraw_network_lsa(PeerID peer, OspfTypes::RouterID link_state_id);

    /**
     * Refresh the Network-LSAs.
     *
     * @param peerid the peer that needs its Network-LSA refreshed.
     * @param lsar the Network-LSA itself.
     * @param timer is the Network-LSA being refreshed due to the
     * timer firing?
     */
    void refresh_network_lsa(PeerID peerid, Lsa::LsaRef lsar,
			     bool timer = false);

    /**
     * Create an LSA that will be used to announce the default route
     * into "stub" and "nssa" areas.
     */
    void generate_default_route();

    /**
     * Find the default route LSA in the database if it exists.
     */
    bool find_default_route(size_t& index);

    // Temporary storage used by save_default_route() and
    // restore_default_route().
    Lsa::LsaRef _saved_default_route;
    
    /**
     * If the default route LSA is in the database remove it.
     * Typically to stop it being purged when the area type changes or
     * summarisation is disable.
     */
    void save_default_route();

    /**
     * If the default route LSA should be in the database put it
     * back. Either from the previously saved or generate a new one if
     * necessary. Typically paired with save_default_route().
     */
    void restore_default_route();

    /**
     * Withdraw the default route LSA if it exists.
     * Set the LSA to MaxAge and floods.
     */
    void withdraw_default_route();

    /**
     * Refresh the default route LSA.
     * Increments the sequence and floods updates the cost if it has
     * changed.
     */
    void refresh_default_route();

    /**
     * Add a network to be announced.
     */
//     void add_network(PeerID peer, IPNet<A> network);

    /**
     * Remove a network to be announced.
     */
//     void remove_network(PeerID peer, IPNet<A> network);

    /**
     * @return the type of this area.
     */
    OspfTypes::AreaType get_area_type() const { return _area_type; }

    /**
     * Get the options that are sent in hello packets, data
     * description packets, LSA headers (OSPFv2),  Router-LSAs
     * (OSPFv3) and Network-LSAs (OSPFv3).
     */
    uint32_t get_options() {
	return _ospf.get_peer_manager().compute_options(get_area_type());
    }

    /**
     * Receive LSAs
     * 
     * @param peerid that the LSAs arrived on.
     * @param nid neighbourID that the LSAs arrived on.
     * @param lsas list of recived lsas.
     * @param direct_ack list of direct acks to send in response to the LSA
     * @param delayed_ack list of delayed acks to send in response to the LSA
     * @param backup true if the receiving interface was in state backup.
     * @param dr true if the LSA was received from the designated router.
     */
    void receive_lsas(PeerID peerid, OspfTypes::NeighbourID nid,
		      list<Lsa::LsaRef>& lsas, 
		      list<Lsa_header>& direct_ack,
		      list<Lsa_header>& delayed_ack,
		      bool backup, bool dr);

    /**
     * Returned by compare_lsa.
     */
    enum LsaSearch {
	NOMATCH,	// No matching LSA was found.
	EQUIVALENT,	// The two LSAs are considered equivalent.
	NEWER,		// The offered LSA is newer than the database copy.
	OLDER,		// The offered LSA is older than the database copy.
    };

    /**
     * Compare two LSAs.
     *
     * @param candidate offered LSA
     * @param current equivalent to the database copy.
     *
     * @return LsaSearch that describes the type of match.
     */
    LsaSearch compare_lsa(const Lsa_header& candidate,
			  const Lsa_header& current) const;

    /**
     * Compare this LSA to 
     *
     * @param Lsa_header that is being sought.
     * 
     * @return LsaSearch that describes the type of match.
     */
    LsaSearch compare_lsa(const Lsa_header&) const;

    /**
     * @return true if this is a newer LSA than we already have.
     */
    bool newer_lsa(const Lsa_header&) const;

    /**
     * Fetch a list of lsas given a list of requests.
     *
     * The age fields of the returned LSAs will be correctly set.
     *
     * @param requests list of requests
     * @param lsas list of LSAs
     *
     * @return True if *all* the requests have been satisfied. If an LSA
     * can not be found False is returned and the state of the lsas
     * list is undefined; hence should not be used.
     * 
     */
    bool get_lsas(const list<Ls_request>& requests,
		  list<Lsa::LsaRef>& lsas);

    /**
     * Open database
     *
     * Used only by the peer to generate the database description packets.
     *
     * @param empty true if the database is empty.
     * @return Database Handle
     */
    DataBaseHandle open_database(bool& empty);

    /**
     * Is this a valid entry to be returned by the database.
     *
     * This method is for internal use and its use is not recommended.
     *
     * @return true if this entry is valid.
     */
    bool valid_entry_database(size_t index);

    /**
     * Is there another database entry following this one.
     *
     * This method is for internal use and its use is not recommended.
     *
     * @return true if there is a subsequent entry.
     */
    bool subsequent(DataBaseHandle& dbh);

    /**
     * Next database entry
     *
     * @param last true if this is the last entry.
     *
     * @return The next LSA in the database.
     */
    Lsa::LsaRef get_entry_database(DataBaseHandle& dbh, bool& last);

    /**
     * Close the database
     *
     * @param dbd Database descriptor
     */
    void close_database(DataBaseHandle& dbh);

    /**
     * Clear the database.
     */
    void clear_database();

    /**
     * All self originated LSAs of this type MaxAge them.
     */
    void maxage_type_database(uint16_t type);

    /**
     * Is this the backbone area?
     */
    bool backbone() const {
	return OspfTypes::BACKBONE == _area;
    }

    bool backbone(OspfTypes::AreaID area) const {
	return OspfTypes::BACKBONE == area;
    }

    /**
     * Print link state database.
     */
    void testing_print_link_state_database() const;

    /**
     * Testing entry point to add this router Router-LSA to the
     * database replacing the one that is already there.
     */
    bool testing_replace_router_lsa(Lsa::LsaRef lsar) {
	RouterLsa *rlsa = dynamic_cast<RouterLsa *>(lsar.get());
	XLOG_ASSERT(rlsa);
	XLOG_ASSERT(rlsa->get_self_originating());
	XLOG_ASSERT(_ospf.get_router_id() ==
		    rlsa->get_header().get_link_state_id());
	XLOG_ASSERT(_ospf.get_router_id() ==
		    rlsa->get_header().get_advertising_router());

	size_t index;
	if (find_lsa(_router_lsa, index)) {
	    delete_lsa(_router_lsa, index, true);
	}
	_router_lsa = lsar;
	add_lsa(_router_lsa);
	return true;
    }

    /**
     * Testing entry point to add an LSA to the database.
     */
    bool testing_add_lsa(Lsa::LsaRef lsar) {
	return add_lsa(lsar);
    }

    /**
     * Testing entry point to delete an LSA from the database.
     */
    bool testing_delete_lsa(Lsa::LsaRef lsar) {
	size_t index;
	if (find_lsa(lsar, index)) {
	    delete_lsa(lsar, index, true);
	    return true;
	}
	XLOG_FATAL("Attempt to delete LSA that is not in database \n%s",
		   cstring(*lsar));
	return false;
    }

    /**
     * Testing enty point to force a toal routing computation.
     */
    void testing_routing_total_recompute() {
	routing_total_recompute();
    }

    string str() {
	return "Area " + pr_id(_area);
    }

 private:
    Ospf<A>& _ospf;			// Reference to the controlling class.

    OspfTypes::AreaID _area;		// Area: That is represented.
    OspfTypes::AreaType _area_type;	// Type of this area.
    map<OspfTypes::RouterID,bool> _vlinks;	// Virtual link endpoints.
    set<OspfTypes::RouterID> _tmp;	// temporary storage for
					// virtual links.
    bool _summaries;			// True if summaries should be
					// generated into a stub area.
    bool _stub_default_announce;	// Announce a default route into
					// stub or nssa
    uint32_t _stub_default_cost;	// The cost of the default
					// route that is injected into
					// a stub area.
    bool _external_flooding;		// True if AS-External-LSAs
					// are being flooded.

#ifdef	UNFINISHED_INCREMENTAL_UPDATE
    Spt<Vertex> _spt;			// SPT computation unit.
#endif

    Lsa::LsaRef _invalid_lsa;		// An invalid LSA to overwrite slots
    Lsa::LsaRef _router_lsa;		// This routers router LSA.
    vector<Lsa::LsaRef> _db;		// Database of LSAs.
    deque<size_t> _empty_slots;		// Available slots in the Database.
    uint32_t _last_entry;		// One past last entry in
					// database. A value of 0 is
					// an empty database.
    uint32_t _allocated_entries;	// Number of allocated entries.
    
    uint32_t _readers;			// Number of database readers.
    
    DelayQueue<Lsa::LsaRef> _queue;	// Router LSA queue.

    XorpTimer _reincarnate_timer;	// Wait for the LSAs to be purged.
    list<Lsa::LsaRef> _reincarnate;	// Self-originated LSAs where
					// the sequence number has
					// reached MaxSequenceNumber.

#ifdef	UNFINISHED_INCREMENTAL_UPDATE
    uint32_t _TransitCapability;	// Used by the spt computation.

    // XXX - This needs a better name.
    struct Bucket {
	Bucket(size_t index, bool known) : _index(index), _known(known)
	{}
	size_t _index;
	bool _known;
    };

    list<Bucket> _new_lsas;		// Indexes of new LSAs that
					// have arrived recently.
#else
    bool _TransitCapability;		// Does this area support
					// transit traffic?

    void set_transit_capability(bool t) {
	_TransitCapability = t;
    }

    bool get_transit_capability() const {
	return _TransitCapability;
    }
#endif

    /**
     * Internal state that is required about each peer.
     */
    struct PeerState {
	PeerState()
	    : _up(false)
	{}
	bool _up;			// True if peer is enabled.
	list<RouterLink> _router_links;	// Router links for this peer
    };

    typedef ref_ptr<PeerState> PeerStateRef;
    typedef map<PeerID, PeerStateRef> PeerMap;
    PeerMap _peers;		// Peers of this area.

    uint32_t _routing_recompute_delay;	// How many seconds to wait
					// before recompting.
    XorpTimer _routing_recompute_timer;	// Timer to cause recompute.
    
    // How to handle Type-7 LSAs at the border.
    OspfTypes::NSSATranslatorRole _translator_role;
    OspfTypes::NSSATranslatorState _translator_state;
    bool _type7_propagate;		// How to set the propagate bit.

    /**
     * Range to be summarised or suppressed from other areas.
     */
    struct Range {
	bool _advertise;	// Should this range be advertised.
    };

    Trie<A, Range> _area_range;	// Area range for summary generation.

    /**
     * Networks with same network number but different prefix lengths
     * can generate the same link state ID. When generating a new LSA
     * if a collision occurs use: 
     * RFC 2328 Appendix E. An algorithm for assigning Link State IDs
     * to resolve the clash. Summary-LSAs only.
     */
    void unique_link_state_id(Lsa::LsaRef lsar);

    /**
     * Networks with same network number but different prefix lengths
     * can generate the same link state ID. When looking for an LSA
     * make sure that there the lsar that matches the net is
     * found. Summary-LSAs only.
     */
    bool unique_find_lsa(Lsa::LsaRef lsar, const IPNet<A>& net, size_t& index);

    /**
     * Set the network components of the LSA.
     */
    void summary_network_lsa_set_net(SummaryNetworkLsa *snlsa, IPNet<A> net);


    Lsa::LsaRef summary_network_lsa(IPNet<A> net, RouteEntry<A>& rt);

    /**
     * Generate a Summary-LSA for an intra area path taking into
     * account area ranges. An announcement may not generate an LSA
     * and a withdraw may not cause an LSA to be removed.
     */
    Lsa::LsaRef summary_network_lsa_intra_area(OspfTypes::AreaID area,
					       IPNet<A> net,
					       RouteEntry<A>& rt,
					       bool& announce);
    /**
     * Construct a summary LSA if appropriate.
     * @param announce true if this in an announce false if its a withdraw.
     * @return the LSA can be empty.
     */
    Lsa::LsaRef summary_build(OspfTypes::AreaID area, IPNet<A> net,
			      RouteEntry<A>& rt, bool& announce);

    /**
     * Announce this Summary-LSA to all neighbours and refresh it as
     * appropriate.
     */
    void refresh_summary_lsa(Lsa::LsaRef lsar);

    /**
     * Start aging LSA.
     *
     * All non self originated LSAs must be aged and when they reach
     * MAXAGE flooded and flushed.
     */
    bool age_lsa(Lsa::LsaRef lsar);

    /**
     * This LSA has reached MAXAGE so flood it to all the peers of
     * this area. If its an external LSA flood it to all areas.
     */
    void maxage_reached(Lsa::LsaRef lsar, size_t index);

    /**
     * Prematurely age self originated LSAs, remove them from the
     * database flood with age set to MAXAGE.
     */
    void premature_aging(Lsa::LsaRef lsar, size_t index);

    /**
     * Increment the sequence number of of this LSA, most importantly
     * handle the sequence number reaching MaxSequenceNumber. 
     */
    void increment_sequence_number(Lsa::LsaRef lsar);

    /**
     * Update the age and increment the sequence number of of this
     * LSA, most importantly handle the sequence number reaching
     * MaxSequenceNumber.
     */
    void update_age_and_seqno(Lsa::LsaRef lsar, const TimeVal& now);

    /**
     * Process an LSA where the sequence number has reached MaxSequenceNumber.
     */
    void max_sequence_number_reached(Lsa::LsaRef lsar);

    /**
     * Reincarnate LSAs that have gone through the MaxSequenceNumber
     * transition. Called on a periodic timer.
     */
    bool reincarnate();

    /**
     * Add this LSA to the database.
     *
     * The LSA must have an updated age field. 
     *
     * @param lsar LSA to add.
     * @return true on success
     */
    bool add_lsa(Lsa::LsaRef lsar);

    /**
     * Delete this LSA from the database.
     *
     * @param lsar LSA to delete.
     * @param index into database.
     * @param invalidate if true as well as removing from the database
     * mark the LSA as invalid.
     * @return true on success
     */
    bool delete_lsa(Lsa::LsaRef lsar, size_t index, bool invalidate);

    /**
     * Update this LSA in the database.
     *
     * @param lsar LSA to update.
     * @param index into database.
     * @return true on success
     */
    bool update_lsa(Lsa::LsaRef lsar, size_t index);

    /**
     * Find LSA matching this request.
     *
     * @param lsr that is being sought.
     * @param index into LSA database if search succeeded.
     *
     * @return true if an LSA was found. 
     */
    bool find_lsa(const Ls_request& lsr, size_t& index) const;

    /**
     * Find LSA matching this request.
     *
     * @param lsar that is being sought.
     * @param index into LSA database if search succeeded.
     *
     * @return true if an LSA was found. 
     */
    bool find_lsa(Lsa::LsaRef lsar, size_t& index) const;

    /**
     * Find Network-LSA.
     *
     * @param link_state_id
     * @param index into LSA database if search succeeded.
     *
     * @return true if an LSA was found. 
     */
    bool find_network_lsa(uint32_t link_state_id, size_t& index) const;

    /**
     * Compare this LSA to 
     *
     * @param Lsa_header that is being sought.
     * @param index into LSA database if search succeeded.
     * 
     * @return LsaSearch that describes the type of match.
     */
    LsaSearch compare_lsa(const Lsa_header&, size_t& index) const;

    /**
     * Update router links.
     *
     * A peer has just changed state, or the refresh timer has fired,
     * so update the router lsa and publish.
     *
     * @return true if something changed.
     */
    bool update_router_links();

    /*
     * Send this LSA to all our peers.
     *
     * @param peerid The peer this LSA arrived on.
     * @param nid The neighbour this LSA arrived on so don't reflect.
     * @param lsar The LSA to publish
     * @param multicast_on_peer Did this LSA get multicast on this peer.
     */
    void publish(const PeerID peerid, const OspfTypes::NeighbourID nid,
		 Lsa::LsaRef lsar, bool& multicast_on_peer) const;

    /*
     * Send this LSA to all our peers.
     *
     * @param lsar The LSA to publish
     */
    void publish_all(Lsa::LsaRef lsar);

    /**
     * Send (push) any queued LSAs.
     */
    void push_lsas();

    /**
     * Return the setting of the propagate bit in a Type-7-LSA.
     */
    bool external_propagate_bit(Lsa::LsaRef lsar) const {
	XLOG_ASSERT(lsar->type7());
	return Options(_ospf.get_version(),lsar->get_header().get_options())
	    .get_p_bit();
    }

    /**
     * Take a Type-7-LSA that has arrived on the wire and translate if
     * required.
     */
    void external_type7_translate(Lsa::LsaRef lsar);

    /**
     * Send this LSA to all area's.
     *
     * This is an AS-External-LSA being sent to other areas.
     *
     * @param lsar The LSA to publish
     */
    void external_flood_all_areas(Lsa::LsaRef lsar);

    /**
     * Notify all areas this is the last of the AS-External-LSAs.
     */
    void external_push_all_areas();

    /**
     * @return true if any of the neigbours are in state Exchange or Loading.
     */
    bool neighbours_exchange_or_loading() const;

    /**
     * Is this LSA on this neighbours link state request list.
     * @param peerid
     * @param nid
     *
     * @return true if it is.
     */
    bool on_link_state_request_list(const PeerID peerid,
				    const OspfTypes::NeighbourID nid,
				    Lsa::LsaRef lsar) const;

    /**
     * Generate a BadLSReq event.
     *
     * @param peerid
     * @param nid
     */
    bool event_bad_link_state_request(const PeerID peerid,
				      const OspfTypes::NeighbourID nid) const;

    /**
     * Send this LSA directly to the neighbour. Do not place on
     * retransmission list.
     *
     * @param peerid
     * @param nid
     * @param lsar
     *
     * @return true on success
     */
    bool send_lsa(const PeerID peerid, const OspfTypes::NeighbourID nid,
		  Lsa::LsaRef lsar) const;

    /**
     * Check this LSA to see if its link state id matched any of the
     * routers interfaces.
     *
     * @param lsar LSA to check.
     * A dummy argument is used to force an IPv4 and an IPv6 instance
     * of this method to be generated. Isn't C++ cool?
     */
    bool self_originated_by_interface(Lsa::LsaRef lsar, A = A::ZERO()) const;

    /**
     * If this is a self-originated LSA do the appropriate processing.
     * RFC 2328 Section 13.4. Receiving self-originated LSAs
     *
     * @param lsar received LSA.
     * @param match if true this LSA has matched a self-originated LSA
     * already in the database.
     * @param index if match is true the index into the database for
     * the matching LSA.
     *
     * @return true if this is a self-orignated LSA.
     */
    bool self_originated(Lsa::LsaRef lsar, bool match, size_t index);

    /**
     * Create a vertex for this router.
     */
    void RouterVertex(Vertex& v);

    /**
     * Prepare for routing changes.
     */
    void routing_begin();

    /**
     * Add this LSA to the routing computation.
     *
     * The calls to this method are bracketed between a call to
     * routing begin and routing end.
     *
     * @param lsar LSA to be added to the database.
     * @param known true if this LSA is already in the database.
     */
    void routing_add(Lsa::LsaRef lsar, bool known);

    /**
     * Remove this LSA from the routing computation.
     *
     * The calls to this method are *NOT* bracketed between a call to
     * routing begin and routing end.
     */
    void routing_delete(Lsa::LsaRef lsar);

    /**
     * Routing changes are completed.
     * 1) Update the routing table if necessary.
     * 2) Possibly generate new summary LSAs.
     */
    void routing_end();

    /**
     * Schedule recomputing the whole table.
     */
    void routing_schedule_total_recompute();

    /**
     * Callback routine that causes route recomputation.
     */
    void routing_timer();

    /**
     * Totally recompute the routing table from the LSA database.
     */
    void routing_total_recompute();
    void routing_total_recomputeV2();
    void routing_total_recomputeV3();

    /**
     * Compute the discard routes related to area ranges.
     */
    void routing_area_ranges(list<RouteCmd<Vertex> >& r);
    void routing_area_rangesV2(list<RouteCmd<Vertex> >& r);
    void routing_area_rangesV3(list<RouteCmd<Vertex> >& r);

    /**
     * Compute the inter-area routes.
     */
    void routing_inter_area();
    void routing_inter_areaV2();
    void routing_inter_areaV3();

    /**
     * Compute the transit area routes.
     */
    void routing_transit_area();
    void routing_transit_areaV2();
    void routing_transit_areaV3();

    /**
     * Compute the AS external routes.
     */
    void routing_as_external();
    void routing_as_externalV2();
    void routing_as_externalV3();


    /**
     * RFC 3101 Section 2.5. (6) (e) Calculating Type-7 AS external routes.
     *
     * Return true if the current LSA should be replaced by the
     * candidate LSA.
     */
    bool routing_compare_externals(Lsa::LsaRef current,
				   Lsa::LsaRef candidate) const;

    /**
     * Does this Router-LSA point back to the router link that points
     * at it.
     *
     * @param rl_type type of link p2p or vlink
     * @param link_state_id from RouterLSA that points at rlsa.
     * @param rl link from RouterLSA that points at rlsa.
     * @param rlsa that is pointed at by previous two arguments.
     * @param metric (out argument) from rlsa back to link_state_id if the back
     * pointer exists.
     * @param interface_address (out argument) if the back pointer exists.
     *
     * @return true if the back pointer exists also fill in the metric
     * and interface address.
     * value.
     */
    bool bidirectional(RouterLink::Type rl_type,
		       const uint32_t link_state_id,
		       const RouterLink& rl,
		       RouterLsa *rlsa,
		       uint16_t& metric,
		       uint32_t& interface_address);

    /**
     * Does this Network-LSA point back to the router link that points
     * at it.
     */
    bool bidirectional(const uint32_t link_state_id, const RouterLink& rl,
		       NetworkLsa *nlsa) const;

    /**
     * Does the Router-LSA point at the Network-LSA that points at it.
     *
     * @param interface_address (out argument) if the back pointer exists.
     *
     * @return true if Router-LSA points at the Network-LSA.
     */
    bool bidirectional(RouterLsa *rlsa, NetworkLsa *nlsa,
		       uint32_t& interface_address);

    /**
     * Add this newly arrived or changed Router-LSA to the SPT.
     */
    void routing_router_lsaV2(Spt<Vertex>& spt, const Vertex& src,
			      RouterLsa *rlsa);

    void routing_router_link_p2p_vlinkV2(Spt<Vertex>& spt, const Vertex& src,
					 RouterLsa *rlsa, RouterLink rl);

    void routing_router_link_transitV2(Spt<Vertex>& spt, const Vertex& src,
				       RouterLsa *rlsa, RouterLink rl);

    void routing_router_link_stubV2(Spt<Vertex>& spt, const Vertex& src,
				    RouterLsa *rlsa, RouterLink rl);

    /**
     * Add this newly arrived or changed Router-LSA to the SPT.
     */
    void routing_router_lsaV3(Spt<Vertex>& spt, const Vertex& v,
			      RouterLsa *rlsa);

};

/**
 * DataBase Handle
 *
 * Holds state regarding position in the database
 */
class DataBaseHandle {
 public:
    DataBaseHandle() : _position(0), _last_entry(0), _valid(false)
    {}

    DataBaseHandle(bool v, uint32_t last_entry)
	: _position(0), _last_entry(last_entry), _valid(v)
    {}

    uint32_t position() const {
	XLOG_ASSERT(valid());
	return _position;
    }

    uint32_t last() const {
	XLOG_ASSERT(valid());
	return _last_entry;
    }

    void advance(bool& last) { 
	XLOG_ASSERT(valid());
	XLOG_ASSERT(_last_entry != _position);
	_position++; 
	last = _last_entry == _position;
    }

    bool valid() const { return _valid; }

    void invalidate() { _valid = false; }

 private:
    uint32_t _position;		// Position in database.
    uint32_t _last_entry;	// One past last entry, for an empty
				// database value would be 0.
    bool _valid;		// True if this handle is valid.
};

#endif // __OSPF_AREA_ROUTER_HH__

Generated by: pavlin on possum.icir.org on Wed Aug 2 15:36:38 2006, using kdoc $.