Source: ../../fea/iftree.hh


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

// 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/fea/iftree.hh,v 1.37 2006/07/25 09:46:42 pavlin Exp $

#ifndef __FEA_IFTREE_HH__
#define __FEA_IFTREE_HH__

#include "libxorp/xorp.h"

#include <map>
#include <string>

#include "libxorp/ipv4.hh"
#include "libxorp/ipv6.hh"
#include "libxorp/mac.hh"

/**
 * Base class for Fea configurable items where the modifications need
 * to be held over and propagated later, ie changes happen during a
 * transaction but are propagated during the commit.
 */
class IfTreeItem {
public:
    IfTreeItem() : _st(CREATED), _soft(false) {}
    virtual ~IfTreeItem() {}

public:
    enum State {
	NO_CHANGE = 0x00,
	CREATED = 0x01,
	DELETED = 0x02,
	CHANGED = 0x04
    };

    inline bool set_state(State st) {
	if (bits(st) > 1) {
	    return false;
	}
	_st = st;
	return true;
    }

    inline State state() const 			{ return _st; }

    inline bool mark(State st) {
	if (bits(st) > 1) {
	    return false;
	}
	if (st & (CREATED | DELETED)) {
	    _st = st;
	    return true;
	}
	if (_st & (CREATED | DELETED)) {
	    return true;
	}
	_st = st;
	return true;
    }
    inline bool is_marked(State st) const	{ return st == _st; }

    inline void set_soft(bool en)	{ _soft = en; }

    inline bool is_soft() const		{ return _soft; }

    /**
     * Virtual method to be implemented to flush out state associated
     * objects, ie if an object is marked CREATED or CHANGED it should be
     * marked NO_CHANGE, if an object is marked DELETED, it should be
     * removed from the relevant container and destructed.
     */
    virtual void finalize_state() = 0;

    string str() const;

protected:
    inline static uint32_t bits(State st) {
	uint32_t c;
	for (c = 0; st != NO_CHANGE; c += st & 0x01)
	    st = State(st >> 1);
	return c;
    }

    State _st;
    bool  _soft;
};


// Classes derived from IfTreeItem
class IfTree;
class IfTreeInterface;
class IfTreeVif;
class IfTreeAddr4;
class IfTreeAddr6;

/**
 * Container class for Fea Interface objects in a system.
 */
class IfTree : public IfTreeItem {
public:
    typedef map<const string, IfTreeInterface> IfMap;

    /**
     * Remove all interface state from the interface tree.
     */
    void clear();

    /**
     * Create a new interface.
     *
     * @param ifname interface name.
     *
     * @return true on success, false if an error.
     */
    bool add_if(const string& ifname);

    /**
     * Label interface as ready for deletion.  Deletion does not occur
     * until finalize_state() is called.
     *
     * @param ifname name of interface to be labelled.
     *
     * @return true on success, false if ifname is invalid.
     */
    bool remove_if(const string& ifname);

    /**
     * Create a new interface or update its state if it already exists.
     *
     * @param other_iface the interface with the state to copy from.
     *
     * @return true on success, false if an error.
     */
    bool update_if(const IfTreeInterface& other_iface);

    /**
     * Get iterator of corresponding to named interface.
     *
     * @param ifname interface name to find iterator for.
     *
     * @return iterator, will be equal to ifs().end() if invalid.
     */
    inline IfMap::iterator get_if(const string& ifname);

    /**
     * Get iterator corresponding to an interface with a given
     * physical index.
     *
     * @param ifindex interface index to find iterator for.
     *
     * @return iterator, will be equal to ifs().end() if invalid.
     */
    IfMap::iterator get_if(uint32_t ifindex);

    /**
     * Get iterator of corresponding to named interface.
     *
     * @param ifname interface name to find iterator for.
     *
     * @return iterator, will be equal to ifs().end() if invalid.
     */
    inline IfMap::const_iterator get_if(const string& ifname) const;

    /**
     * Get iterator corresponding to an interface with a given
     * physical index.
     *
     * @param ifindex interface index to find iterator for.
     *
     * @return iterator, will be equal to ifs().end() if invalid.
     */
    IfMap::const_iterator get_if(uint32_t ifindex) const;

    inline const IfMap& ifs() const { return _ifs; }

    inline IfMap& ifs() { return _ifs; }

    /**
     * Align user supplied configuration with the device configuration.
     *
     * Inside the FEA there may be multiple configuration representations,
     * typically one the user modifies and one that mirrors the hardware.
     * Errors may occur pushing the user config down onto the hardware and
     * we need a method to update the user config from the h/w config that
     * exists after the config push.  We can't just copy the h/w config since
     * the user config is restricted to configuration set by the user.
     * The alignment works as follows:
     * - If the item in the local tree is "disabled", then the state is copied
     *   but the item is still marked as "disabled". Otherwise, the rules
     *   below are applied.
     * - If an item from the local tree is not in the other tree,
     *   it is marked as deleted in the local tree.
     *   However, if an interface from the local tree is marked as "soft"
     *   or "discard_emulated", and is not in the other tree, the interface
     *   is not marked as deleted in the local tree.
     * - If an item from the local tree is in the other tree,
     *   its state is copied from the other tree to the local tree.
     *   However, if an item from the local tree is marked as "flipped",
     *   it will be set in the local tree even if it is not set in the other
     *   tree.
     * - If an item from the other tree is not in the local tree, we do NOT
     *   copy it to the local tree.
     *
     * @param other the configuration tree to align state with.
     * @return modified configuration structure.
     */
    IfTree& align_with(const IfTree& other);

    /**
     * Prepare configuration for pushing and replacing previous configuration.
     *
     * If the previous configuration is to be replaced with new configuration,
     * we need to prepare the state that will delete, update, and add the
     * new state as appropriate.
     * The preparation works as follows:
     * - All items in the local tree are preserved and marked as created.
     * - All items in the other tree that are not in the local tree are
     *   added to the local tree and are marked as deleted.
     *   Only if the interface is marked as "soft" or "discard_emulated",
     *   or if the item in the other state is marked as disabled, then it
     *   is not added.
     *
     * @param other the configuration tree to be used to prepare the
     * replacement state.
     * @return modified configuration structure.
     */
    IfTree& prepare_replacement_state(const IfTree& other);

    /**
     * Prune bogus deleted state.
     * 
     * If an item from the local tree is marked as deleted, but is not
     * in the other tree, then it is removed.
     * 
     * @param old_iftree the old tree with the state that is used as reference.
     * @return the modified configuration tree.
     */
    IfTree& prune_bogus_deleted_state(const IfTree& old_iftree);

    /**
     * Track modifications from the live config state as read from the kernel.
     *
     * All interface-related modifications as received by the observer
     * mechanism are recorded in a local copy of the interface tree
     * (the live configuration tree). Some of those modifications however
     * should be propagated to the XORP local configuration tree.
     * This method updates a local configuration tree with only the relevant
     * modifications of the live configuration tree:
     * - Only if an item is in the local configuration tree, its status
     *   may be modified.
     * - If the "no_carrier" flag of an interface is changed in the live
     *   configuration tree, the corresponding flag in the local configuration
     *   tree is updated.
     * 
     * @param other the live configuration tree whose modifications are
     * tracked.
     * @return modified configuration structure.
     */
    IfTree& track_live_config_state(const IfTree& other);

    /**
     * Delete interfaces labelled as ready for deletion, call finalize_state()
     * on remaining interfaces, and set state to NO_CHANGE.
     */
    void finalize_state();

    /**
     * @return string representation of IfTree.
     */
    string str() const;

protected:
    IfMap	_ifs;
};


/**
 * Fea class for holding physical interface state.
 */
class IfTreeInterface : public IfTreeItem {
public:
    typedef map<const string, IfTreeVif> VifMap;

    IfTreeInterface(const string& ifname);

    inline const string& name() const	{ return _ifname; }

    inline const string& ifname() const	{ return _ifname; }

    inline uint32_t pif_index() const	{ return _pif_index; }
    inline void set_pif_index(uint32_t v) { _pif_index = v; mark(CHANGED); }

    inline bool enabled() const		{ return _enabled; }

    inline void set_enabled(bool en)	{ _enabled = en; mark(CHANGED); }

    inline uint32_t mtu() const		{ return _mtu; }

    inline void set_mtu(uint32_t mtu)	{ _mtu = mtu; mark(CHANGED); }

    inline const Mac& mac() const	{ return _mac; }

    inline void set_mac(const Mac& mac)	{ _mac = mac; mark(CHANGED); }

    inline bool no_carrier() const	{ return _no_carrier; }

    inline void set_no_carrier(bool v)	{ _no_carrier = v; mark(CHANGED); }

    inline bool discard() const		{ return _discard; }

    inline void set_discard(bool discard) {
	_discard = discard;
	mark(CHANGED);
    }

    inline bool is_discard_emulated() const { return _is_discard_emulated; }

    inline void set_discard_emulated(bool v) {
	_is_discard_emulated = v;
	mark(CHANGED);
    }

    /**
     * Get the flipped flag.
     *
     * This flag indicates the interface's enable/disable status
     * has been flipped (i.e., first disabled, and then enabled).
     *
     * @return true if the interface has been flipped, otherwise false.
     */
    inline bool flipped() const		{ return _flipped; }

    /**
     * Set the value of the flipped flag.
     *
     * @param v if true, then the flipped flag is enabled, otherwise is
     * disabled.
     */
    inline void set_flipped(bool v)	{ _flipped = v; mark(CHANGED); }

    /**
     * Get the system-specific interface flags.
     *
     * Typically, this value is read from the underlying system, and is
     * used only for internal purpose.
     *
     * @return the system-specific interface flags.
     */
    inline uint32_t if_flags() const	{ return _if_flags; }

    /**
     * Store the system-specific interface flags.
     *
     * Typically, this value is read from the underlying system, and is
     * used only for internal purpose.
     *
     * @param if_flags the value of the system-specific interface flags to
     * store.
     */
    inline void set_if_flags(uint32_t if_flags) { _if_flags = if_flags; mark(CHANGED); }

    inline const VifMap& vifs() const	{ return _vifs; }
    inline VifMap& vifs()		{ return _vifs; }

    bool add_vif(const string& vifname);

    bool remove_vif(const string& vifname);

    inline VifMap::iterator get_vif(const string& vifname);

    inline VifMap::const_iterator get_vif(const string& vifname) const;

    /**
     * Copy state of internal variables from another IfTreeInterface.
     */
    inline void copy_state(const IfTreeInterface& o)
    {
	set_pif_index(o.pif_index());
	set_enabled(o.enabled());
	set_mtu(o.mtu());
	set_mac(o.mac());
	set_no_carrier(o.no_carrier());
	set_flipped(o.flipped());
	set_if_flags(o.if_flags());
    }

    /**
     * Test if the interface-specific internal state is same.
     *
     * @param o the IfTreeInterface to compare against.
     * @return true if the interface-specific internal state is same.
     */
    inline bool is_same_state(const IfTreeInterface& o)
    {
	return ((pif_index() == o.pif_index())
		&& (enabled() == o.enabled())
		&& (mtu() == o.mtu())
		&& (mac() == o.mac())
		&& (no_carrier() == o.no_carrier())
		&& (flipped() == o.flipped())
		&& (if_flags() == o.if_flags()));
    }

    void finalize_state();

    string str() const;

protected:
    const string _ifname;
    uint32_t	 _pif_index;
    bool 	 _enabled;
    bool	 _discard;
    bool	 _is_discard_emulated;
    uint32_t 	 _mtu;
    Mac 	 _mac;
    bool	 _no_carrier;
    bool	 _flipped;	// If true, interface -> down, then -> up
    uint32_t	 _if_flags;	// The system-specific interface flags
    VifMap	 _vifs;
};


/**
 * Fea class for virtual (logical) interface state.
 */
class IfTreeVif : public IfTreeItem {
public:
    typedef map<const IPv4, IfTreeAddr4> V4Map;
    typedef map<const IPv6, IfTreeAddr6> V6Map;

    IfTreeVif(const string& ifname, const string& vifname);

    const string& ifname() const	{ return _ifname; }

    const string& vifname() const	{ return _vifname; }

    inline uint32_t pif_index() const	{ return _pif_index; }
    inline void set_pif_index(uint32_t v) { _pif_index = v; mark(CHANGED); }

    inline bool enabled() const		{ return _enabled; }
    inline bool broadcast() const	{ return _broadcast; }
    inline bool loopback() const	{ return _loopback; }
    inline bool point_to_point() const	{ return _point_to_point; }
    inline bool multicast() const	{ return _multicast; }

    inline void set_enabled(bool en)	{ _enabled = en; mark(CHANGED); }
    inline void set_broadcast(bool v)	{ _broadcast = v; mark(CHANGED); }
    inline void set_loopback(bool v)	{ _loopback = v; mark(CHANGED); }
    inline void set_point_to_point(bool v) { _point_to_point = v; mark(CHANGED); }
    inline void set_multicast(bool v)	{ _multicast = v; mark(CHANGED); }

    inline const V4Map& v4addrs() const	{ return _v4addrs; }
    inline V4Map& v4addrs()		{ return _v4addrs; }

    inline const V6Map& v6addrs() const	{ return _v6addrs; }
    inline V6Map& v6addrs()		{ return _v6addrs; }

    inline V4Map::iterator get_addr(const IPv4& a);

    inline V6Map::iterator get_addr(const IPv6& a);

    inline V4Map::const_iterator get_addr(const IPv4& a) const;

    inline V6Map::const_iterator get_addr(const IPv6& a) const;

    /**
     * Add address.
     *
     * @param v4addr address to be added.
     *
     * @return true on success, false if an error.
     */
    bool add_addr(const IPv4& v4addr);

    /**
     * Mark address as DELETED.  Deletion occurs when finalize_state is called.
     *
     * @param v4addr address to labelled.
     *
     * @return true on success, false if address does not exist.
     */
    bool remove_addr(const IPv4& v4addr);

    /**
     * Add address.
     *
     * @param v6addr address to be added.
     *
     * @return true on success, false if an error.
     */
    bool add_addr(const IPv6& v6addr);

    /**
     * Mark address as DELETED.  Deletion occurs when finalize_state is called.
     *
     * @param v6addr address to labelled.
     *
     * @return true on success, false if address does not exist.
     */
    bool remove_addr(const IPv6& v6addr);

    /**
     * Copy state of internal variables from another IfTreeVif.
     */
    inline void copy_state(const IfTreeVif& o)
    {
	set_pif_index(o.pif_index());
	set_enabled(o.enabled());
	set_broadcast(o.broadcast());
	set_loopback(o.loopback());
	set_point_to_point(o.point_to_point());
	set_multicast(o.multicast());
    }

    /**
     * Test if the vif-specific internal state is same.
     *
     * @param o the IfTreeVif to compare against.
     * @return true if the vif-specific internal state is same.
     */
    inline bool is_same_state(const IfTreeVif& o)
    {
	return ((pif_index() == o.pif_index())
		&& (enabled() == o.enabled())
		&& (broadcast() == o.broadcast())
		&& (loopback() == o.loopback())
		&& (point_to_point() == o.point_to_point())
		&& (multicast() == o.multicast()));
    }

    void finalize_state();

    string str() const;

protected:
    const string _ifname;
    const string _vifname;

    uint32_t	 _pif_index;
    bool 	 _enabled;
    bool	 _broadcast;
    bool	 _loopback;
    bool	 _point_to_point;
    bool	 _multicast;

    V4Map	 _v4addrs;
    V6Map	 _v6addrs;
};


/**
 * Class for holding an IPv4 interface address and address related items.
 */
class IfTreeAddr4 : public IfTreeItem {
public:
    IfTreeAddr4(const IPv4& addr)
	: IfTreeItem(), _addr(addr), _enabled(false), _broadcast(false),
	  _loopback(false), _point_to_point(false), _multicast(false),
	  _prefix_len(0)
    {}

    inline const IPv4& addr() const	{ return _addr; }

    inline bool enabled() const		{ return _enabled; }
    inline bool broadcast() const	{ return _broadcast; }
    inline bool loopback() const	{ return _loopback; }
    inline bool point_to_point() const	{ return _point_to_point; }
    inline bool multicast() const	{ return _multicast; }

    inline void set_enabled(bool en)	{ _enabled = en; mark(CHANGED); }
    inline void set_broadcast(bool v)	{ _broadcast = v; mark(CHANGED); }
    inline void set_loopback(bool v)	{ _loopback = v; mark(CHANGED); }
    inline void set_point_to_point(bool v) { _point_to_point = v; mark(CHANGED); }
    inline void set_multicast(bool v)	{ _multicast = v; mark(CHANGED); }

    /**
     * Get prefix length associates with address.
     */
    inline uint32_t prefix_len() const	{ return _prefix_len; }

    /**
     * Set prefix length associate with address.
     * @return true on success, false if prefix length is invalid.
     */
    bool set_prefix_len(uint32_t prefix_len);

    /**
     * Get the broadcast address.
     * @return the broadcast address or IPv4::ZERO() if there is no
     * broadcast address set.
     */
    IPv4 bcast() const;

    /**
     * Set the broadcast address.
     * @param baddr the broadcast address.
     */
    void set_bcast(const IPv4& baddr);

    /**
     * Get the endpoint address of a point-to-point link.
     * @return the broadcast address or IPv4::ZERO() if there is no
     * broadcast address set.
     */
    IPv4 endpoint() const;

    /**
     * Set the endpoint address of a point-to-point link.
     * @param oaddr the endpoint address.
     */
    void set_endpoint(const IPv4& oaddr);

    /**
     * Copy state of internal variables from another IfTreeAddr4.
     */
    inline void copy_state(const IfTreeAddr4& o)
    {
	set_enabled(o.enabled());
	set_broadcast(o.broadcast());
	set_loopback(o.loopback());
	set_point_to_point(o.point_to_point());
	set_multicast(o.multicast());
	if (o.broadcast())
	    set_bcast(o.bcast());
	if (o.point_to_point())
	    set_endpoint(o.endpoint());
	set_prefix_len(o.prefix_len());
    }

    /**
     * Test if the address-specific internal state is same.
     *
     * @param o the IfTreeAddr4 to compare against.
     * @return true if the address-specific internal state is same.
     */
    inline bool is_same_state(const IfTreeAddr4& o)
    {
	return ((enabled() == o.enabled())
		&& (broadcast() == o.broadcast())
		&& (loopback() == o.loopback())
		&& (point_to_point() == o.point_to_point())
		&& (multicast() == o.multicast())
		&& (bcast() == o.bcast())
		&& (endpoint() == o.endpoint())
		&& (prefix_len() == o.prefix_len()));
    }

    void finalize_state();

    string str() const;

protected:
    IPv4	_addr;

    bool 	_enabled;
    bool	_broadcast;
    bool	_loopback;
    bool	_point_to_point;
    bool	_multicast;

    IPv4	_oaddr;		// Other address - p2p endpoint or bcast addr
    uint32_t	_prefix_len;	// The prefix length
};


/**
 * Class for holding an IPv6 interface address and address related items.
 */
class IfTreeAddr6 : public IfTreeItem
{
public:
    IfTreeAddr6(const IPv6& addr)
	: IfTreeItem(), _addr(addr), _enabled(false),
	  _loopback(false), _point_to_point(false), _multicast(false),
	  _prefix_len(0)
    {}

    const IPv6& addr() const		{ return _addr; }

    inline bool enabled() const		{ return _enabled; }
    inline bool loopback() const	{ return _loopback; }
    inline bool point_to_point() const	{ return _point_to_point; }
    inline bool multicast() const	{ return _multicast; }

    inline void set_enabled(bool en)	{ _enabled = en; mark(CHANGED); }
    inline void set_loopback(bool v)	{ _loopback = v; mark(CHANGED); }
    inline void set_point_to_point(bool v) { _point_to_point = v; mark(CHANGED); }
    inline void set_multicast(bool v)	{ _multicast = v; mark(CHANGED); }

    /**
     * Get prefix length associated with address.
     */
    inline uint32_t prefix_len() const	{ return _prefix_len; }

    /**
     * Set prefix length associate with address.
     * @return true on success, false if prefix length is invalid.
     */
    bool set_prefix_len(uint32_t prefix_len);

    IPv6 endpoint() const;

    void set_endpoint(const IPv6& oaddr);

    /**
     * Copy state of internal variables from another IfTreeAddr6.
     */
    inline void copy_state(const IfTreeAddr6& o)
    {
	set_enabled(o.enabled());
	set_loopback(o.loopback());
	set_point_to_point(o.point_to_point());
	set_multicast(o.multicast());
	if (o.point_to_point())
	    set_endpoint(o.endpoint());
	set_prefix_len(o.prefix_len());
    }

    /**
     * Test if the address-specific internal state is same.
     *
     * @param o the IfTreeAddr6 to compare against.
     * @return true if the address-specific internal state is same.
     */
    inline bool is_same_state(const IfTreeAddr6& o)
    {
	return ((enabled() == o.enabled())
		&& (loopback() == o.loopback())
		&& (point_to_point() == o.point_to_point())
		&& (multicast() == o.multicast())
		&& (endpoint() == o.endpoint())
		&& (prefix_len() == o.prefix_len()));
    }

    void finalize_state();

    string str() const;

protected:
    IPv6	_addr;

    bool 	_enabled;
    bool	_loopback;
    bool	_point_to_point;
    bool	_multicast;

    IPv6	_oaddr;		// Other address - p2p endpoint
    uint32_t	_prefix_len;	// The prefix length
};


//
// Inline IfTree methods
//

inline IfTree::IfMap::iterator
IfTree::get_if(const string& ifname)
{
    return _ifs.find(ifname);
}

inline IfTree::IfMap::const_iterator
IfTree::get_if(const string& ifname) const
{
    return _ifs.find(ifname);
}

//
// Inline IfTreeInterface methods
//

inline IfTreeInterface::VifMap::iterator
IfTreeInterface::get_vif(const string& vifname)
{
    return _vifs.find(vifname);
}

inline
IfTreeInterface::VifMap::const_iterator
IfTreeInterface::get_vif(const string& vifname) const
{
    return _vifs.find(vifname);
}

//
// Inline IfTreeVif methods
//

inline IfTreeVif::V4Map::iterator
IfTreeVif::get_addr(const IPv4& a)
{
    return _v4addrs.find(a);
}

inline IfTreeVif::V6Map::iterator
IfTreeVif::get_addr(const IPv6& a)
{
    return _v6addrs.find(a);
}

inline IfTreeVif::V4Map::const_iterator
IfTreeVif::get_addr(const IPv4& a) const
{
    return _v4addrs.find(a);
}

inline IfTreeVif::V6Map::const_iterator
IfTreeVif::get_addr(const IPv6& a) const
{
    return _v6addrs.find(a);
}

#endif // __FEA_IFTREE_HH__

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