// -*- 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/rib/rt_tab_redist.hh,v 1.20 2009/01/05 18:31:07 jtc Exp $ #ifndef __RIB_RT_TAB_REDIST_HH__ #define __RIB_RT_TAB_REDIST_HH__ #include "rt_tab_base.hh" template <typename A> class Redistributor; template <typename A> class RedistOutput; template <typename A> class RedistPolicy; /** * Comparitor to allow nets to be stored in a sorted container. */ template <typename A> struct RedistNetCmp { bool operator() (const IPNet<A>& l, const IPNet<A>& r) const; }; /** * @short RouteTable used to redistribute routes. * * The RedistTable is used to redistribute routes from a routing table * back out to a routing protocol. For example, when you want to * redistribute BGP routes into OSPF. * * For most operations the RedistTable is essentially a passthrough. * It keeps track of nets it hears add and deletes for so when route * @ref Redistributor objects are added to the RedistTable they can * announce the existing routes at startup. * * Design note: RedistTable uses a set of IPNet's to cache routes - this * should be route entry pointers with an appropriate comparitor (not pointer * value based). */ template<class A> class RedistTable : public RouteTable<A> { public: typedef set<IPNet<A>,RedistNetCmp<A> > RouteIndex; public: /** * Constructor. * * Plumbs RedistTable in RIB graph after from_table. * * @param from_table table to redistribute routes from. */ RedistTable(const string& tablename, RouteTable<A>* from_table); /** * Destructor. * * Unplumbs table and deletes Redistributor object instances previously * added with add_redistributor and not previously removed with * remove_redistributor. */ ~RedistTable(); /** * Add a redistributor to announce existing routes and future updates * to. */ void add_redistributor(Redistributor<A>* r); /** * Remove a redistributor. */ void remove_redistributor(Redistributor<A>* r); /** * Find redistributor with given name attribute. */ Redistributor<A>* redistributor(const string& name); // // Standard RouteTable methods // int add_route(const IPRouteEntry<A>& route, RouteTable<A>* caller); int delete_route(const IPRouteEntry<A>* route, RouteTable<A>* caller); const IPRouteEntry<A>* lookup_route(const IPNet<A>& net) const; const IPRouteEntry<A>* lookup_route(const A& addr) const; RouteRange<A>* lookup_route_range(const A& addr) const; TableType type() const { return REDIST_TABLE; } RouteTable<A>* parent() { return _parent; } void replumb(RouteTable<A>* old_parent, RouteTable<A>* new_parent); string str() const; /** * Get nets of live routes seen by RedistTable since it was * instantiated. */ const RouteIndex& route_index() const { return _rt_index; } protected: RouteTable<A>* _parent; // Immediately upstream table. May // differ from _from_table if a // Deletion table or another redist // table has been plumbed in. RouteIndex _rt_index; list<Redistributor<A>*> _outputs; }; /** * Controller class that takes routes from RedistTable and passes them * on via RedistOutput. * * Instances of this class are constructed when one routing protocol * requests route distribution from another. Instances walk the * routes available in the RedistTable route index, resolve them, and * announce them via the RedistOutput. Future updates received * from the RedistTable are propagated via the Redistributor instances * associated with it. */ template <typename A> class Redistributor { public: class RedistEventInterface { // Methods only available to RedistTable. void did_add(const IPRouteEntry<A>& ipr); void will_delete(const IPRouteEntry<A>& ipr); void did_delete(const IPRouteEntry<A>& ipr); friend class RedistTable<A>; friend class Redistributor<A>; public: RedistEventInterface(Redistributor<A>* r) : _r(r) {} private: Redistributor<A>* _r; }; class OutputEventInterface { // Methods only available to RedistOutput. These are // events it can tell us about. void low_water(); void high_water(); void fatal_error(); friend class RedistOutput<A>; friend class Redistributor<A>; public: OutputEventInterface(Redistributor<A>* r) : _r(r) {} private: Redistributor<A>* _r; }; public: Redistributor(EventLoop& e, const string& name); virtual ~Redistributor(); const string& name() const; void set_redist_table(RedistTable<A>* rt); /** * Bind RedistOutput to Redistributor instance. The output * should be dynamically allocated with new. When a new * redistributor output is set, the existing output is removed via * delete. The RedistOutput is deleted by the * Redistributor when the Redistributor is destructed. */ void set_output(RedistOutput<A>* output); /** * Bind policy object to Redistributor instance. The policy * should be dynamically allocated with new. When a new policy is * set, the existing policy is removed via delete. The policy is * deleted by the Redistributor when the Redistributor is * destructed. */ void set_policy(RedistPolicy<A>* policy); /** * Determine if policy accepts updates to route. * * @return true if associated property accepts update to route or * if no policy is enforced, false otherwise. */ bool policy_accepts(const IPRouteEntry<A>& ipr) const; /** * Method available to instances of RedistTable to announce events * to the Redistributor instance. */ RedistEventInterface& redist_event() { return _rei; } /** * Method available to instances of RedistOutput to * announce transport events to the Redistributor instance. */ OutputEventInterface& output_event() { return _oei; } /** * Indicate dump status. When Redistributor is first connected it dumps * existing routes to it's RedistOutput. * * @return true if route dump is in process, false if route dump is * either not started or finished. */ bool dumping() const { return _dumping; } private: /** * Start initial route dump when a RedistTable is associated with instance * through set_redist_table(). */ void start_dump(); void finish_dump(); void schedule_dump_timer(); void unschedule_dump_timer(); void dump_a_route(); const IPNet<A>& last_dumped_net() const { return _last_net; } RedistTable<A>* redist_table() { return _table; } RedistOutput<A>* output() { return _output; } private: // The following are not implemented Redistributor(const Redistributor<A>&); Redistributor<A>& operator=(const Redistributor<A>&); // These are nested classes and need to be friends to invoke methods in // enclosing class. friend class RedistEventInterface; friend class OutputEventInterface; private: EventLoop& _e; string _name; RedistTable<A>* _table; RedistOutput<A>* _output; RedistPolicy<A>* _policy; RedistEventInterface _rei; OutputEventInterface _oei; bool _dumping; // Announcing existing routes bool _blocked; // Output above high water IPNet<A> _last_net; // Last net announced XorpTimer _dtimer; static const IPNet<A> NO_LAST_NET; // Indicator for last net inval }; /** * Base class for propagaing output of route add and delete messages. */ template <typename A> class RedistOutput { public: RedistOutput(Redistributor<A>* r); virtual ~RedistOutput(); virtual void add_route(const IPRouteEntry<A>& ipr) = 0; virtual void delete_route(const IPRouteEntry<A>& ipr) = 0; /** * Method called by Redistributor to indicate start of initial * route dump. This occurs when an output is first attached to * the redistributor to announce the existing routes. */ virtual void starting_route_dump() = 0; /** * Method called by Redistributor to indicate end of initial * route dump. This occurs when an output is first attached to * the redistributor to announce the existing routes. */ virtual void finishing_route_dump() = 0; protected: void announce_low_water() { _r->output_event().low_water(); } void announce_high_water() { _r->output_event().high_water(); } void announce_fatal_error() { _r->output_event().fatal_error(); } private: // The following are not implemented RedistOutput(const RedistOutput<A>&); RedistOutput<A>& operator=(const RedistOutput<A>&); private: Redistributor<A>* _r; }; // ---------------------------------------------------------------------------- // Inline RedistTable methods template <typename A> inline bool RedistNetCmp<A>::operator() (const IPNet<A>& l, const IPNet<A>& r) const { if (l.prefix_len() != r.prefix_len()) return l.prefix_len() < r.prefix_len(); return l.masked_addr() < r.masked_addr(); } #endif // __RIB_RT_TAB_REDIST_HH__