Source: ../../fea/ifconfig.hh


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

// Copyright (c) 2001-2005 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/fea/ifconfig.hh,v 1.43 2005/03/25 05:41:55 pavlin Exp $

#ifndef __FEA_IFCONFIG_HH__
#define __FEA_IFCONFIG_HH__

#include "ifconfig_get.hh"
#include "ifconfig_set.hh"
#include "ifconfig_observer.hh"
#include "iftree.hh"

class EventLoop;
class IfConfigGet;
class IfConfigSet;
class IfConfigObserver;
class IfConfigErrorReporterBase;
class IfConfigUpdateReporterBase;
class NexthopPortMapper;


/**
 * Base class for pushing and pulling interface configurations down to
 * the particular platform.
 */
class IfConfig {
public:
    /**
     * Constructor.
     *
     * @param eventloop the event loop.
     * @param ur update reporter that receives updates through when
     *           configurations are pushed down and when triggered
     *		 spontaneously on the underlying platform.
     * @param er error reporter that errors are propagated through when
     *           configurations are pushed down.
     * @param nexthop_port_mapper the next-hop port mapper.
     */
    IfConfig(EventLoop& eventloop, IfConfigUpdateReporterBase& ur,
	     IfConfigErrorReporterBase& er,
	     NexthopPortMapper& nexthop_port_mapper);

    /**
     * Virtual destructor (in case this class is used as base class).
     */
    virtual ~IfConfig();

    /**
     * Get a reference to the @ref EventLoop instance.
     *
     * @return a reference to the @ref EventLoop instance.
     */
    EventLoop& eventloop() { return _eventloop; }

    /**
     * Get a reference to the @ref NexthopPortMapper instance.
     *
     * @return a reference to the @ref NexthopPortMapper instance.
     */
    NexthopPortMapper& nexthop_port_mapper() { return _nexthop_port_mapper; }

    /**
     * Get error reporter associated with IfConfig.
     */
    inline IfConfigErrorReporterBase&	er() { return _er; }

    IfTree& live_config() { return (_live_config); }
    void    set_live_config(const IfTree& it) { _live_config = it; }

    const IfTree& pulled_config()	{ return (_pulled_config); }
    IfTree& pushed_config()		{ return (_pushed_config); }

    int register_ifc_get_primary(IfConfigGet *ifc_get);
    int register_ifc_set_primary(IfConfigSet *ifc_set);
    int register_ifc_observer_primary(IfConfigObserver *ifc_observer);
    int register_ifc_get_secondary(IfConfigGet *ifc_get);
    int register_ifc_set_secondary(IfConfigSet *ifc_set);
    int register_ifc_observer_secondary(IfConfigObserver *ifc_observer);

    IfConfigGet&	ifc_get_primary() { return *_ifc_get_primary; }
    IfConfigSet&	ifc_set_primary() { return *_ifc_set_primary; }
    IfConfigObserver&	ifc_observer_primary() { return *_ifc_observer_primary; }

    IfConfigGet&	ifc_get_ioctl() { return _ifc_get_ioctl; }
    IfConfigSetClick&	ifc_set_click() { return _ifc_set_click; }

    /**
     * Setup the unit to behave as dummy (for testing purpose).
     *
     * @return XORP_OK on success, otherwise XORP_ERROR.
     */
    int set_dummy();

    /**
     * Test if running in dummy mode.
     * 
     * @return true if running in dummy mode, otherwise false.
     */
    bool is_dummy() const { return _is_dummy; }

    /**
     * Start operation.
     *
     * @param error_msg the error message (if error).
     * @return XORP_OK on success, otherwise XORP_ERROR.
     */
    int start(string& error_msg);

    /**
     * Stop operation.
     *
     * @param error_msg the error message (if error).
     * @return XORP_OK on success, otherwise XORP_ERROR.
     */
    int stop(string& error_msg);

    /**
     * Return true if the underlying system supports IPv4.
     * 
     * @return true if the underlying system supports IPv4, otherwise false.
     */
    bool have_ipv4() const { return _have_ipv4; }

    /**
     * Return true if the underlying system supports IPv6.
     * 
     * @return true if the underlying system supports IPv6, otherwise false.
     */
    bool have_ipv6() const { return _have_ipv6; }

    /**
     * Test if the underlying system supports IPv4.
     * 
     * @return true if the underlying system supports IPv4, otherwise false.
     */
    bool test_have_ipv4() const;

    /**
     * Test if the underlying system supports IPv6.
     * 
     * @return true if the underlying system supports IPv6, otherwise false.
     */
    bool test_have_ipv6() const;

    /**
     * Enable/disable Click support.
     *
     * @param enable if true, then enable Click support, otherwise disable it.
     */
    void enable_click(bool enable);

    /**
     * Start Click support.
     *
     * @param error_msg the error message (if error).
     * @return XORP_OK on success, otherwise XORP_ERROR.
     */
    int start_click(string& error_msg);

    /**
     * Stop Click support.
     *
     * @param error_msg the error message (if error).
     * @return XORP_OK on success, otherwise XORP_ERROR.
     */
    int stop_click(string& error_msg);

    /**
     * Specify the external program to generate the kernel-level Click
     * configuration.
     *
     * @param v the name of the external program to generate the kernel-level
     * Click configuration.
     */
    void set_kernel_click_config_generator_file(const string& v);

    /**
     * Enable/disable kernel-level Click support.
     *
     * @param enable if true, then enable the kernel-level Click support,
     * otherwise disable it.
     */
    void enable_kernel_click(bool enable);

    /**
     * Enable/disable installing kernel-level Click on startup.
     *
     * @param enable if true, then install kernel-level Click on startup.
     */
    void enable_kernel_click_install_on_startup(bool enable);

    /**
     * Specify the list of kernel Click modules to load on startup if
     * installing kernel-level Click on startup is enabled.
     *
     * @param modules the list of kernel Click modules to load.
     */
    void set_kernel_click_modules(const list<string>& modules);

    /**
     * Specify the kernel-level Click mount directory.
     *
     * @param directory the kernel-level Click mount directory.
     */
    void set_kernel_click_mount_directory(const string& directory);

    /**
     * Enable/disable user-level Click support.
     *
     * @param enable if true, then enable the user-level Click support,
     * otherwise disable it.
     */
    void enable_user_click(bool enable);

    /**
     * Specify the user-level Click command file.
     *
     * @param v the name of the user-level Click command file.
     */
    void set_user_click_command_file(const string& v);

    /**
     * Specify the extra arguments to the user-level Click command.
     *
     * @param v the extra arguments to the user-level Click command.
     */
    void set_user_click_command_extra_arguments(const string& v);

    /**
     * Specify whether to execute on startup the user-level Click command.
     *
     * @param v if true, then execute the user-level Click command on startup.
     */
    void set_user_click_command_execute_on_startup(bool v);

    /**
     * Specify the address to use for control access to the user-level
     * Click.
     *
     * @param v the address to use for control access to the user-level Click.
     */
    void set_user_click_control_address(const IPv4& v);

    /**
     * Specify the socket port to use for control access to the user-level
     * Click.
     *
     * @param v the socket port to use for control access to the user-level
     * Click.
     */
    void set_user_click_control_socket_port(uint32_t v);

    /**
     * Specify the configuration file to be used by user-level Click on
     * startup.
     *
     * @param v the name of the configuration file to be used by user-level
     * Click on startup.
     */
    void set_user_click_startup_config_file(const string& v);

    /**
     * Specify the external program to generate the user-level Click
     * configuration.
     *
     * @param v the name of the external program to generate the user-level
     * Click configuration.
     */
    void set_user_click_config_generator_file(const string& v);

    /**
     * Push IfTree structure down to platform.  Errors are reported
     * via the constructor supplied ErrorReporter instance.
     *
     * Note that on return some of the interface tree configuration state
     * may be modified.
     *
     * @param config the configuration to be pushed down.
     * @return true on success, otherwise false.
     */
    bool push_config(IfTree& config);

    /**
     * Pull up current config from platform.
     *
     * @return the platform IfTree.
     */
    const IfTree& pull_config();

    void flush_config() { _live_config = IfTree(); }

    IfTreeInterface *get_if(IfTree& it, const string& ifname);
    IfTreeVif *get_vif(IfTree& it, const string& ifname,
		       const string& vifname);

    /**
     * Get error message associated with push operation.
     */
    const string& push_error() const;

    /**
     * Check IfTreeInterface and report updates to IfConfigUpdateReporter.
     *
     * @return true if there were updates to report, otherwise false.
     */
    bool   report_update(const IfTreeInterface& fi,
			 bool is_system_interfaces_reportee);

    /**
     * Check IfTreeVif and report updates to IfConfigUpdateReporter.
     *
     * @return true if there were updates to report, otherwise false.
     */
    bool   report_update(const IfTreeInterface& fi, const IfTreeVif& fv,
			 bool is_system_interfaces_reportee);

    /**
     * Check IfTreeAddr4 and report updates to IfConfigUpdateReporter.
     *
     * @return true if there were updates to report, otherwise false.
     */
    bool   report_update(const IfTreeInterface&	fi,
			 const IfTreeVif&	fv,
			 const IfTreeAddr4&     fa,
			 bool  is_system_interfaces_reportee);

    /**
     * Check IfTreeAddr6 and report updates to IfConfigUpdateReporter.
     *
     * @return true if there were updates to report, otherwise false.
     */
    bool   report_update(const IfTreeInterface&	fi,
			 const IfTreeVif&	fv,
			 const IfTreeAddr6&     fa,
			 bool  is_system_interfaces_reportee);

    /**
     * Report that updates were completed to IfConfigUpdateReporter.
     */
    void   report_updates_completed(bool is_system_interfaces_reportee);

    /**
     * Check every item within IfTree and report updates to
     * IfConfigUpdateReporter.
     */
    void   report_updates(const IfTree& it, bool is_system_interfaces_reportee);

    void	map_ifindex(uint32_t if_index, const string& ifname);
    void	unmap_ifindex(uint32_t if_index);
    const char*	find_ifname(uint32_t if_index) const;
    uint32_t	find_ifindex(const string& ifname) const;

    const char*	get_insert_ifname(uint32_t if_index);
    uint32_t	get_insert_ifindex(const string& ifname);

private:

    EventLoop&			_eventloop;
    IfConfigUpdateReporterBase&	_ur;
    IfConfigErrorReporterBase&	_er;
    NexthopPortMapper&		_nexthop_port_mapper;

    //
    // A cache of associative array of interface names to interface index.
    // Needed because the RTM_IFANNOUNCE upcall is called after the interface
    // name is deleted from the kernel.
    //
    typedef map<uint32_t, string> IfIndex2NameMap;
    IfIndex2NameMap	_ifnames;

    IfTree		_live_config;	// The IfTree with live config
    IfTree		_pulled_config;	// The IfTree when we pull the config
    IfTree		_pushed_config;	// The IfTree when we push the config

    IfConfigGet*		_ifc_get_primary;
    IfConfigSet*		_ifc_set_primary;
    IfConfigObserver*		_ifc_observer_primary;
    list<IfConfigGet*>		_ifc_gets_secondary;
    list<IfConfigSet*>		_ifc_sets_secondary;
    list<IfConfigObserver*>	_ifc_observers_secondary;

    //
    // The primary mechanisms to get interface-related information
    // from the underlying system.
    //
    // XXX: Ordering is important: the last that is supported
    // is the one to use.
    //
    IfConfigGetDummy		_ifc_get_dummy;
    IfConfigGetIoctl		_ifc_get_ioctl;
    IfConfigGetSysctl		_ifc_get_sysctl;
    IfConfigGetGetifaddrs	_ifc_get_getifaddrs;
    IfConfigGetProcLinux	_ifc_get_proc_linux;
    IfConfigGetNetlink		_ifc_get_netlink;

    //
    // The secondary mechanisms to get interface-related information
    // from the underlying system.
    //
    // XXX: Ordering is not important.
    //
    IfConfigGetClick		_ifc_get_click;

    //
    // The primary mechanisms to set interface-related information
    // within the underlying system.
    //
    // XXX: Ordering is important: the last that is supported
    // is the one to use.
    //
    IfConfigSetDummy		_ifc_set_dummy;
    IfConfigSetIoctl		_ifc_set_ioctl;
    IfConfigSetNetlink		_ifc_set_netlink;

    //
    // The secondary mechanisms to get interface-related information
    // from the underlying system.
    //
    // XXX: Ordering is not important.
    //
    IfConfigSetClick		_ifc_set_click;

    //
    // The primary mechanisms to observe whether the interface-related
    // information within the underlying system has changed.
    //
    // XXX: Ordering is important: the last that is supported
    // is the one to use.
    //
    IfConfigObserverDummy	_ifc_observer_dummy;
    IfConfigObserverRtsock	_ifc_observer_rtsock;
    IfConfigObserverNetlink	_ifc_observer_netlink;

    //
    // Misc other state
    //
    bool	_have_ipv4;
    bool	_have_ipv6;
    bool	_is_dummy;
    bool	_is_running;
};

/**
 * @short Base class for propagating update information on from IfConfig.
 *
 * When the platform @ref IfConfig updates interfaces it can report
 * updates to an IfConfigUpdateReporter.  The @ref IfConfig instance
 * takes a pointer to the IfConfigUpdateReporter object it should use.
 */
class IfConfigUpdateReporterBase {
public:
    enum Update { CREATED, DELETED, CHANGED };

    virtual ~IfConfigUpdateReporterBase() {}

    virtual void interface_update(const string& ifname,
				  const Update& u,
				  bool  is_system_interfaces_reportee) = 0;

    virtual void vif_update(const string& ifname,
			    const string& vifname,
			    const Update& u,
			    bool  is_system_interfaces_reportee) = 0;

    virtual void vifaddr4_update(const string& ifname,
				 const string& vifname,
				 const IPv4&   addr,
				 const Update& u,
				 bool  is_system_interfaces_reportee) = 0;

    virtual void vifaddr6_update(const string& ifname,
				 const string& vifname,
				 const IPv6&   addr,
				 const Update& u,
				 bool  is_system_interfaces_reportee) = 0;

    virtual void updates_completed(bool is_system_interfaces_reportee) = 0;
};

/**
 * @short A class to replicate update notifications to multiple reporters.
 */
class IfConfigUpdateReplicator : public IfConfigUpdateReporterBase {
public:
    typedef IfConfigUpdateReporterBase::Update Update;

public:
    virtual ~IfConfigUpdateReplicator();

    /**
     * Add a reporter instance to update notification list.
     *
     * @return true on success, false if object already receiving updates or
     * could not be added.
     */
    bool add_reporter(IfConfigUpdateReporterBase* rp);

    /**
     * Remove a reporter instance from update notification list.
     *
     * @return true on success, false if instance is not on the
     * receiving updates list.
     */
    bool remove_reporter(IfConfigUpdateReporterBase* rp);

    /**
     * Forward interface update notification to reporter instances on
     * update notification list.
     */
    void interface_update(const string& ifname,
			  const Update& u,
			  bool  is_system_interfaces_reportee);

    /**
     * Forward virtual interface update notification to reporter
     * instances on update notification list.
     */
    void vif_update(const string& ifname,
		    const string& vifname,
		    const Update& u,
		    bool is_system_interfaces_reportee);

    /**
     * Forward virtual interface address update notification to
     * reporter instances on update notification list.
     */
    void vifaddr4_update(const string& ifname,
			 const string& vifname,
			 const IPv4&   addr,
			 const Update& u,
			 bool is_system_interfaces_reportee);

    /**
     * Forward virtual interface address update notification to
     * reporter instances on update notification list.
     */
    void vifaddr6_update(const string& ifname,
			 const string& vifname,
			 const IPv6&   addr,
			 const Update& u,
			 bool is_system_interfaces_reportee);

    /**
     * Forward notification that updates were completed to
     * reporter instances on update notification list.
     */
    void updates_completed(bool is_system_interfaces_reportee);

protected:
    list<IfConfigUpdateReporterBase*> _reporters;
};

/**
 * @short Base class for propagating error information on from IfConfig.
 *
 * When the platform @ref IfConfig updates interfaces it can report
 * errors to an IfConfigErrorReporterBase.  The @ref IfConfig instance
 * takes a pointer to the IfConfigErrorReporterBase object it should use.
 */
class IfConfigErrorReporterBase {
public:
    IfConfigErrorReporterBase() : _error_cnt(0) {}
    virtual ~IfConfigErrorReporterBase() {}

    virtual void config_error(const string& error_msg) = 0;

    virtual void interface_error(const string& ifname,
				 const string& error_msg) = 0;

    virtual void vif_error(const string& ifname,
			   const string& vifname,
			   const string& error_msg) = 0;

    virtual void vifaddr_error(const string& ifname,
			       const string& vifname,
			       const IPv4&   addr,
			       const string& error_msg) = 0;

    virtual void vifaddr_error(const string& ifname,
			       const string& vifname,
			       const IPv6&   addr,
			       const string& error_msg) = 0;

    /**
     * @return error message of first error encountered.
     */
    inline const string& first_error() const	{ return _first_error; }

    /**
     * @return error message of last error encountered.
     */
    inline const string& last_error() const	{ return _last_error; }

    /**
     * @return number of errors reported.
     */
    inline uint32_t error_count() const		{ return _error_cnt; }

    /**
     * Reset error count and error message.
     */
    inline void reset() {
	_first_error.erase();
	_last_error.erase();
	_error_cnt = 0;
    }

    inline void	log_error(const string& s) {
	if (0 == _error_cnt)
	    _first_error = s;
	_last_error = s;
	_error_cnt++;
    }

private:
    string	_last_error;	// last error reported
    string	_first_error;	// first error reported

    uint32_t	_error_cnt;	// number of errors reported
};

/**
 * @short Class for propagating error information during IfConfig operations.
 *
 */
class IfConfigErrorReporter : public IfConfigErrorReporterBase {
public:
    IfConfigErrorReporter();

    void config_error(const string& error_msg);

    void interface_error(const string& ifname,
			 const string& error_msg);

    void vif_error(const string& ifname,
		   const string& vifname,
		   const string& error_msg);

    void vifaddr_error(const string& ifname,
		       const string& vifname,
		       const IPv4&   addr,
		       const string& error_msg);

    void vifaddr_error(const string& ifname,
		       const string& vifname,
		       const IPv6&   addr,
		       const string& error_msg);

private:
};

#endif // __FEA_IFCONFIG_HH__

Generated by: pavlin on possum.icir.org on Wed Apr 13 21:53:05 2005, using kdoc $.