// -*- c-basic-offset: 4; tab-width: 8; indent-tabs-mode: t -*- // vim:set sts=4 ts=8: // 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/ospf/peer_manager.hh,v 1.101 2009/01/05 18:31:01 jtc Exp $ #ifndef __OSPF_PEER_MANAGER_HH__ #define __OSPF_PEER_MANAGER_HH__ template <typename A> class Ospf; template <typename A> class PeerOut; template <typename A> class AreaRouter; template <typename A> class RouteEntry; template <typename A> class External; template <typename A> class Vlink; /** * Peer Manager: * 1) Monitor the state of the interfaces. An interface going * up/down will be monitored and trigger either adjacency * attempts or new (withdraw) LSAs. * 2) Manage interface configuration state. Control peers and * area state. * 3) Accept incoming hello's and demultiplex to the correct peer. * 4) Manage the set of peers (peers are bound to interface and * area). The peers themselves are hidden and are only * exposed by reference (PeerID). */ template <typename A> class PeerManager { public: PeerManager(Ospf<A>& ospf) : _ospf(ospf), _next_peerid(OspfTypes::ALLPEERS + 1), _external(ospf, _areas) {} ~PeerManager(); /** * Check area type. * * Verify that this area can be set to this area type. */ bool check_area_type(OspfTypes::AreaID area, OspfTypes::AreaType area_type); /** * Create an area router. * @param area * @param area_type * @param permissive if true won't fail if the area already exists. */ bool create_area_router(OspfTypes::AreaID area, OspfTypes::AreaType area_type, bool permissive = true); AreaRouter<A> *get_area_router(OspfTypes::AreaID area); /** * Change the type of this area. */ bool change_area_router_type(OspfTypes::AreaID area, OspfTypes::AreaType area_type); /** * Destroy an area router. */ bool destroy_area_router(OspfTypes::AreaID area); /** * Add area range. */ bool area_range_add(OspfTypes::AreaID area, IPNet<A> net, bool advertise); /** * Delete area range. */ bool area_range_delete(OspfTypes::AreaID area, IPNet<A> net); /** * Change the advertised state of this area. */ bool area_range_change_state(OspfTypes::AreaID area, IPNet<A> net, bool advertise); /** * Get a single lsa from an area. A stateless mechanism to get LSAs. The * client of this interface should start from zero and continue to request * LSAs (incrementing index) until toohigh becomes true. * * @param area database that is being searched. * @param index into database starting from 0. * @param valid true if a LSA has been returned. Some index values do not * contain LSAs. This should not be considered an error. * @param toohigh true if no more LSA exist after this index. * @param self if true this LSA was originated by this router. * @param lsa if valid is true the LSA at index. */ bool get_lsa(const OspfTypes::AreaID area, const uint32_t index, bool& valid, bool& toohigh, bool& self, vector<uint8_t>& lsa); /** * Get a list of all the configured areas. */ bool get_area_list(list<OspfTypes::AreaID>& areas) const; /** * Get a list of all the neighbours. */ bool get_neighbour_list(list<OspfTypes::NeighbourID>& neighbours) const; /** * Get state information about this neighbour. * * @param nid neighbour information is being request about. * @param ninfo if neighbour is found its information. * */ bool get_neighbour_info(OspfTypes::NeighbourID nid, NeighbourInfo& ninfo) const; /** * Convert an interface/vif to a PeerID. * Throw an exception if no mapping is found. */ OspfTypes::PeerID get_peerid(const string& interface, const string& vif) throw(BadPeer); /** * Given a PeerID convert it back to an interface and vif. */ bool get_interface_vif_by_peerid(OspfTypes::PeerID peerid, string& interface, string& vif) const; /** * Is this interface/vif/address enabled? * This is a question asked of the FEA, has the interface/vif been * marked as up. * * @return true if it is. */ bool enabled(const string& interface, const string& vif, A address); /** * Create a peer. * @param interface * @param vif * @param source address of transmitted packets. * @param linktype broadcast or point-2-point, etc... * @param area ID of area * * @return PeerID on success otherwise throw an exception. */ OspfTypes::PeerID create_peer(const string& interface, const string& vif, A source, OspfTypes::LinkType linktype, OspfTypes::AreaID area) throw(BadPeer); /** * Delete a peer. */ bool delete_peer(const OspfTypes::PeerID); /** * Take a peer up or down. */ bool set_state_peer(const OspfTypes::PeerID, bool state); /** * Set the link status of the peer. */ bool set_link_status_peer(const OspfTypes::PeerID, bool state); /** * Add an address to this peer OSPFv3 only. */ bool add_address_peer(const string& interface, const string& vif, OspfTypes::AreaID area, A addr); /** * Remove an address from this peer OSPFv3 only. */ bool remove_address_peer(const OspfTypes::PeerID, OspfTypes::AreaID area, A addr); /** * Set the state of the address on this peer OSPFv3 only. */ bool set_address_state_peer(const OspfTypes::PeerID, OspfTypes::AreaID area, A addr, bool enable); /** * Activate this peer OSPFv3 only. * Called once after the peer is created and every time a new * address is added, but not when an address is deleted. */ bool activate_peer(const string& interface, const string& vif, OspfTypes::AreaID area); /** * Update this peer OSPFv3 only. * Called every time a variable related to this peer is changed. */ bool update_peer(const string& interface, const string& vif, OspfTypes::AreaID area); /** * Update this peer OSPFv3 only. * Reset the addresses that should be advertised by this peer. */ bool recompute_addresses_peer(const OspfTypes::PeerID, OspfTypes::AreaID area); /** * Track the state of a vif. * Callback when the status of the vif changes. */ void vif_status_change(const string& interface, const string& vif, bool state); /** * Track the state of an address. * Callback when the status of the address changes. */ void address_status_change(const string& interface, const string& vif, A source, bool state); /** * Add a neighbour to the peer. */ bool add_neighbour(const OspfTypes::PeerID, OspfTypes::AreaID area, A neighbour_address, OspfTypes::RouterID); /** * Remove a neighbour from the peer. */ bool remove_neighbour(const OspfTypes::PeerID, OspfTypes::AreaID area, A neighbour_address, OspfTypes::RouterID rid); /** * Transmit packets */ bool transmit(const string& interface, const string& vif, A dst, A src, uint8_t* data, uint32_t len); /** * Demultiplex incoming packets to the associated peer. If the * packet contains LSAs send it to the LSA database manager if * appropriate. * * @param interface that packet arrived on * @param vif that packet arrived on * @param packet * @return true if the packet is now owned by the peer manager. */ bool receive(const string& interface, const string& vif, A dst, A src, Packet *packet) throw(BadPeer); /** * Drop all adjacencies and hence clear database. */ bool clear_database(); /** * Queue an LSA for transmission. * * @param peerid to queue the LSA on. * @param peer the LSA arrived on. * @param nid the LSA arrived on. * @param lsar the lsa * @param multicast_on_peer will this LSA get multicast on this peer. * * @return true on success. */ bool queue_lsa(const OspfTypes::PeerID peerid, const OspfTypes::PeerID peer, OspfTypes::NeighbourID nid, Lsa::LsaRef lsar, bool &multicast_on_peer); /** * Send (push) any queued LSAs. */ bool push_lsas(const OspfTypes::PeerID peerid); /** * Get the interface ID of this peer OSPFv3 only. */ uint32_t get_interface_id(const OspfTypes::PeerID peerid); /** * Return a list of the fully adjacent routers. */ bool get_attached_routers(const OspfTypes::PeerID peerid, OspfTypes::AreaID area, list<RouterInfo>& routers); /* * Does this address fall into a configured OSPF network making it * a valid nexthop address. * * @param address under test * * @return true if this address falls into a configured OSPF network. */ bool configured_network(const A address) const; /* * Is this one of the routers interface addresses, used to try and * detect self-originated LSAs. * * @param address under test * * @return true if this a known interface address. */ bool known_interface_address(const A address) const; /** * Are any of the neighbours of this peer in the state exchange or * loading. * * @param peerid * @param area * * @return true if any of the neighbours are in state exchange or loading. */ bool neighbours_exchange_or_loading(const OspfTypes::PeerID peerid, OspfTypes::AreaID area); /** * Is the state of the neighbour with the specified Router ID at * least 2-Way. * * @param peerid * @param area * @param rid Router ID * @param twoway if the neighbour is found true means the * neighbour is at least twoway. * * @return true if the neighbour is found. */ bool neighbour_at_least_two_way(const OspfTypes::PeerID peerid, OspfTypes::AreaID area, OspfTypes::RouterID rid, bool& twoway); /** * Neighbour's source address. * * @param peerid * @param area * @param rid Router ID * @param interface_id Interface ID. * @param neighbour_address set if neighbour is found. * * @return true if the neighbour is found. */ bool get_neighbour_address(const OspfTypes::PeerID peerid, OspfTypes::AreaID area, OspfTypes::RouterID rid, uint32_t interface_id, A& neighbour_address); /** * Is this LSA on this neighbours link state request list. * @param peerid * @param area * @param nid * * @return true if it is. */ bool on_link_state_request_list(const OspfTypes::PeerID peerid, OspfTypes::AreaID area, const OspfTypes::NeighbourID nid, Lsa::LsaRef lsar); /** * Generate a BadLSReq event. * * @param peerid * @param area * @param nid * * @return true if it is. */ bool event_bad_link_state_request(const OspfTypes::PeerID peerid, OspfTypes::AreaID area, const OspfTypes::NeighbourID nid); /** * Send this LSA directly to the neighbour. Do not place on * retransmission list. * * @param peerid * @param area * @param nid * @param lsar * * @return true on success */ bool send_lsa(const OspfTypes::PeerID peerid, OspfTypes::AreaID area, const OspfTypes::NeighbourID nid, Lsa::LsaRef lsar); /** * Upcall from a peer to notify the peer manager that a full * adjacency has been achieved or lost. * * @param peerid * @param rid neighbours router ID. * @param up true if the adjacency has become full, false if a * full adjacency has been lost. */ void adjacency_changed(const OspfTypes::PeerID peerid, OspfTypes::RouterID rid, bool up); /** * 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) const; /** * Send a new Router-LSA in all areas. * * Typically called when one of the Router-LSA flags changes state. */ void refresh_router_lsas() const; /** * Create a virtual link peer. */ bool create_virtual_peer(OspfTypes::RouterID rid); /** * Delete a virtual link peer. */ bool delete_virtual_peer(OspfTypes::RouterID rid); /** * Are any of neighbours of this area a virtual link endpoint. * * @return true if any are. */ bool virtual_link_endpoint(OspfTypes::AreaID area) const; /** * Create a virtual link (Configuration). * * @param rid neighbours router ID. */ bool create_virtual_link(OspfTypes::RouterID rid); /** * Attach this transit area to the neighbours router ID (Configuration). */ bool transit_area_virtual_link(OspfTypes::RouterID rid, OspfTypes::AreaID transit_area); /** * Delete a virtual link (Configuration). * * @param rid neighbours router ID. */ bool delete_virtual_link(OspfTypes::RouterID rid); /** * Bring virtual link up (Upcall from area router). * * @param rid neighbours router ID. * @param source address of packets sent to this neighbour. * @param interface_cost * @param destination address of the neighbour router. */ void up_virtual_link(OspfTypes::RouterID rid, A source, uint16_t interface_cost, A destination); /** * Take this virtual link down (Upcall from area router). */ void down_virtual_link(OspfTypes::RouterID rid); /** * A packet was sent to a peer that rejected it so this may be a * virtual link candidate. */ bool receive_virtual_link(A dst, A src, Packet *packet); /** * Return the number of areas of the specified type. */ uint32_t area_count(OspfTypes::AreaType area_type) const; /** * Is this an internal router? */ bool internal_router_p() const; /** * Is this an area border router? */ bool area_border_router_p() const; /** * Is this a backbone router? */ bool backbone_router_p() const; /** * Is this an AS boundary router? */ bool as_boundary_router_p() const; /** * Compute the options that are sent in hello packets, data * description packets, LSA headers (OSPFv2), Router-LSAs * (OSPFv3) and Network-LSAs (OSPFv3). * */ uint32_t compute_options(OspfTypes::AreaType area_type); // Config (begin) /** * The router ID is about to change. */ void router_id_changing(); #if 0 /** * Set options. */ bool set_options(const PeerID, OspfTypes::AreaID area, uint32_t options); #endif /** * Set the interface address of this peer. */ bool set_interface_address(const OspfTypes::PeerID, A address); /** * Set the hello interval in seconds. */ bool set_hello_interval(const OspfTypes::PeerID, OspfTypes::AreaID area, uint16_t hello_interval); /** * Set router priority. */ bool set_router_priority(const OspfTypes::PeerID, OspfTypes::AreaID area, uint8_t priority); /** * Set the router dead interval in seconds. */ bool set_router_dead_interval(const OspfTypes::PeerID, OspfTypes::AreaID area, uint32_t router_dead_interval); /** * Set interface cost */ bool set_interface_cost(const OspfTypes::PeerID, OspfTypes::AreaID area, uint16_t interface_cost); /** * Set RxmtInterval */ bool set_retransmit_interval(const OspfTypes::PeerID, OspfTypes::AreaID area, uint16_t retransmit_interval); /** * Set InfTransDelay */ bool set_inftransdelay(const OspfTypes::PeerID, OspfTypes::AreaID area, uint16_t inftransdelay); /** * Set a simple password authentication key. * * Note that the current authentication handler is replaced with * a simple password authentication handler. * * @param peerid the peer ID. * @param area the area ID. * @param password the password to set. * @param the error message (if error). * @return true on success, otherwise false. */ bool set_simple_authentication_key(const OspfTypes::PeerID peerid, OspfTypes::AreaID area, const string& password, string& error_msg); /** * Delete a simple password authentication key. * * Note that after the deletion the simple password authentication * handler is replaced with a Null authentication handler. * * @param peerid the peer ID. * @param area the area ID. * @param the error message (if error). * @return true on success, otherwise false. */ bool delete_simple_authentication_key(const OspfTypes::PeerID peerid, OspfTypes::AreaID area, string& error_msg); /** * Set an MD5 authentication key. * * Note that the current authentication handler is replaced with * an MD5 authentication handler. * * @param peerid the peer ID. * @param area the area ID. * @param key_id unique ID associated with key. * @param password phrase used for MD5 digest computation. * @param start_timeval start time when key becomes valid. * @param end_timeval end time when key becomes invalid. * @param max_time_drift the maximum time drift among all routers. * @param the error message (if error). * @return true on success, otherwise false. */ bool set_md5_authentication_key(const OspfTypes::PeerID peerid, OspfTypes::AreaID area, uint8_t key_id, const string& password, const TimeVal& start_timeval, const TimeVal& end_timeval, const TimeVal& max_time_drift, string& error_msg); /** * Delete an MD5 authentication key. * * Note that after the deletion if there are no more valid MD5 keys, * the MD5 authentication handler is replaced with a Null authentication * handler. * * @param peerid the peer ID. * @param area the area ID. * @param key_id the ID of the key to delete. * @param the error message (if error). * @return true on success, otherwise false. */ bool delete_md5_authentication_key(const OspfTypes::PeerID peerid, OspfTypes::AreaID area, uint8_t key_id, string& error_msg); /** * Toggle the passive status of an interface. */ bool set_passive(const OspfTypes::PeerID, OspfTypes::AreaID area, bool passive, bool host); /** * If this is a "stub" or "nssa" area toggle the sending of a default * route. */ bool originate_default_route(OspfTypes::AreaID area, bool enable); /** * Set the StubDefaultCost, the default cost sent in a default route in a * "stub" or "nssa" area. */ bool stub_default_cost(OspfTypes::AreaID area, uint32_t cost); /** * Toggle the sending of summaries into "stub" or "nssa" areas. */ bool summaries(OspfTypes::AreaID area, bool enable); // Config (end) /** * Number of areas this router serves. */ size_t number_of_areas() const { return _areas.size(); } /** * A new route has been added to the routing table announce it to * all areas as it is a candidate for Summary-LSA generation. * * @param area that the route was introduced by. */ void summary_announce(OspfTypes::AreaID area, IPNet<A> net, RouteEntry<A>& rt); /** * A route has been deleted from the routing table. It may * previously have caused a Summary-LSA which now needs to be * withdrawn. * * @param area that the route was introduced by. */ void summary_withdraw(OspfTypes::AreaID area, IPNet<A> net, RouteEntry<A>& rt); /** * A route has been replaced in the routing table. If a generated * Summary-LSA exists it will need to have its metric or nexthop * modified. * * @param area that the route was introduced by. */ void summary_replace(OspfTypes::AreaID area, IPNet<A> net, RouteEntry<A>& rt, RouteEntry<A>& previous_rt, OspfTypes::AreaID previous_area); /** * Send all the summary information to specified area. New areas * or stub areas that change from do not advertise can use this * hook to force all routes to be sent to the specified area. * * @param area that all routes should be sent to. */ void summary_push(OspfTypes::AreaID area); /** * In the specified area is the net covered by an area range. * * @param area being checked. * @param net that may be covered. * @param advertise if the area is covered set to advertise or do * not advertise. * * @return true if the area is covered. */ bool area_range_covered(OspfTypes::AreaID area, IPNet<A> net, bool& advertise); /** * Does the specified area have any area ranges configured. * * The primary purpose is to discover if the backbone area has any * area ranges configured, this is required when an area becomes a * transit area. */ bool area_range_configured(OspfTypes::AreaID area); /** * An AS-External-LSA has arrived from this area announce it to * all others. * * The LSAs should not be scheduled for transmission until the * external_accounce_complete() is seen. In many cases a number of * LSAs may arrive in a single packet, waiting for the * external_announce_complete() offers an opportunity for * aggregation. * */ bool external_announce(OspfTypes::AreaID area, Lsa::LsaRef lsar); /** * Create an AS-External-LSA and announce it to all appropriate * areas. */ bool external_announce(const IPNet<A>& net, const A& nexthop, const uint32_t& metric, const PolicyTags& policytags); /** * An AS-External-LSA is being withdrawn from this area withdraw from * all others. */ bool external_withdraw(OspfTypes::AreaID area, Lsa::LsaRef lsar); /** * Withdraw a previously created and announced AS-External-LSA * from all areas. */ bool external_withdraw(const IPNet<A>& net); /** * Called to complete a series of calls to external_announce(area). */ bool external_announce_complete(OspfTypes::AreaID area); /** * When a new area is configured it can use this method to * * @param area that all AS-External-LSAs should be sent to. */ void external_push(OspfTypes::AreaID area); /** * Re-run the policy filters on all routes. */ void external_push_routes(); /** * Examine self originated AS-external-LSAs that may need to be * suppressed because another router's AS-external-LSA takes * precedence. */ void external_suppress_lsas(OspfTypes::AreaID area); /** * Recompute routing calculation all areas BACKBONE first. */ void routing_recompute_all_areas(); /** * Recompute routing calculation for all transit areas. */ void routing_recompute_all_transit_areas(); private: Ospf<A>& _ospf; // Reference to the controlling class. OspfTypes::PeerID _next_peerid; // Next PeerID to allocate. map<string, OspfTypes::PeerID> _pmap;// Map from interface/vif to PeerID. map<OspfTypes::PeerID, PeerOut<A> *> _peers; // All of our peers map<OspfTypes::AreaID, AreaRouter<A> *> _areas; // All the areas External<A> _external; // Management of AS-External-LSAs. Vlink<A> _vlink; // Management of virtual links uint32_t _normal_cnt; // Number of normal areas. uint32_t _stub_cnt; // Number of stub areas. uint32_t _nssa_cnt; // Number of nssa areas. /** * Generate PeerID. * Internally we want to deal with peers as simple IDs not * interface/vif. * Throw an exception a mapping already exists. */ OspfTypes::PeerID create_peerid(const string& interface, const string& vif) throw(BadPeer); /** * Get rid of this mapping. */ void destroy_peerid(const string& interface, const string& vif) throw(BadPeer); /** * @return true if this route is a candidate for summarisation. */ bool summary_candidate(OspfTypes::AreaID area, IPNet<A> net, RouteEntry<A>& rt); /** * Saved summaries that can be introduced into a new area. */ struct Summary { Summary() {} Summary(OspfTypes::AreaID area, RouteEntry<A>& rt) : _area(area), _rtentry(rt) {} OspfTypes::AreaID _area; RouteEntry<A> _rtentry; }; map<IPNet<A>, Summary> _summaries; /** * Track the number of areas of each type. * * @param area_type being tracked. * @param up true if the area is being created, false if it is * being deleted. */ void track_area_count(OspfTypes::AreaType area_type, bool up); }; #endif // __OSPF_PEER_MANAGER_HH__