// -*- c-basic-offset: 4; tab-width: 8; indent-tabs-mode: t -*-
// vim:set sts=4 ts=8:

// Copyright (c) 2001-2011 XORP, Inc and Others
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License, Version
// 2.1, June 1999 as published by the Free Software Foundation.
// Redistribution and/or modification of this program under the terms of
// any other version of the GNU Lesser 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 Lesser General Public License, Version 2.1, a copy of
// which can be found in the XORP LICENSE.lgpl file.
// 
// XORP, Inc, 2953 Bunker Hill Lane, Suite 204, Santa Clara, CA 95054, USA;
// http://xorp.net

// $XORP: xorp/libxorp/vif.hh,v 1.23 2008/10/02 21:57:36 bms Exp $

#ifndef __LIBXORP_VIF_HH__
#define __LIBXORP_VIF_HH__



#include "xorp.h"
#include "ipv4.hh"
#include "ipv6.hh"
#include "ipvx.hh"
#include "ipvxnet.hh"

/**
 * @short Virtual interface address class.
 * 
 * VifAddr holds information about an address of a virtual interface.
 * A virtual interface may have more than one VifAddr.
 */
class VifAddr {
public:
    /**
     * Constructor for a given address.
     * 
     * @param ipvx_addr the interface address.
     */
    explicit VifAddr(const IPvX& ipvx_addr);

    /**
     * Constructor for a given address, and its associated addresses.
     * 
     * @param ipvx_addr the interface address.
     * @param ipvx_subnet_addr the subnet address.
     * @param ipvx_broadcast_addr the broadcast address (if the interface
     * is broadcast-capable).
     * @param ipvx_peer_addr the peer address (if the interface is
     * point-to-point).
     */
    VifAddr(const IPvX& ipvx_addr, const IPvXNet& ipvx_subnet_addr,
	    const IPvX& ipvx_broadcast_addr, const IPvX& ipvx_peer_addr);

#ifdef XORP_USE_USTL
    VifAddr(); // AF_INET
#endif

    /**
     * Get the interface address.
     * 
     * @return the interface address.
     */
    const IPvX&		addr()		const	{ return (_addr);	}

    /**
     * Get the subnet address.
     * 
     * @return the subnet address of the interface.
     */
    const IPvXNet&	subnet_addr()	const	{ return (_subnet_addr); }

    /**
     * Get the broadcast address.
     * 
     * The broadcast address is valid only if the interface is broadcast
     * capable.
     * 
     * @return the broadcast address of the interface.
     */
    const IPvX&		broadcast_addr() const	{ return (_broadcast_addr); }

    /**
     * Get the peer address.
     * 
     * The peer address is valid only if the interface is point-to-point.
     * 
     * @return the peer address of the interface.
     */
    const IPvX&		peer_addr()	const	{ return (_peer_addr);	}
    
    /**
     * Set the interface address.
     * 
     * @param v the interface address to set to the interface.
     */
    void  set_addr(const IPvX& v)		{ _addr = v;		}

    /**
     * Set the subnet address.
     * 
     * @param v the subnet address to set to the interface.
     */
    void  set_subnet_addr(const IPvXNet& v)	{ _subnet_addr = v;	}

    /**
     * Set the broadcast address.
     * 
     * @param v the broadcast address to set to the interface.
     */
    void  set_broadcast_addr(const IPvX& v)	{ _broadcast_addr = v;	}

    /**
     * Set the peer address.
     * 
     * @param v the peer address to set to the interface.
     */
    void  set_peer_addr(const IPvX& v)		{ _peer_addr = v;	}
    
    /**
     * Test whether if an IPvX address is same as my address.
     * 
     * @param ipvx_addr the address to test whether is the same as my
     * interface address.
     * 
     * @return true if @ref ipvx_addr is same as my interface address,
     * otherwise false.
     */
    bool  is_my_addr(const IPvX& ipvx_addr) const { return (addr() == ipvx_addr); }
    
    /**
     * Test if a given subnet address is a subset of my subnet address.
     * 
     * @param ipvxnet the subnet address to test whether is a subset of
     * my subnet address.
     * 
     * @return true if @ref ipvxnet is a subset of my subnet address,
     * otherwise false.
     */
    bool  is_same_subnet(const IPvXNet& ipvxnet) const;
    
    /**
     * Test whether an address belongs to my subnet address.
     * 
     * @param ipvx_addr the address to test whether it belongs to my subnet
     * address.
     * @return true if @ref ipvx_addr belongs to my subnet address,
     * otherwise false.
     */
    bool  is_same_subnet(const IPvX& ipvx_addr) const;
    
    /**
     * Convert this address from binary form to presentation format.
     * 
     * @return C++ string with the human-readable ASCII representation
     * of the address.
     */
    string str() const;
    
    /**
     * Equality Operator
     * 
     * @param other the right-hand operand to compare against.
     * @return true if the left-hand operand is numerically same as the
     * right-hand operand.
     */
    bool operator==(const VifAddr& other) const;
    
private:
    IPvX	_addr;				// IP address of the vif
    IPvXNet	_subnet_addr;			// Subnet address on the vif
    IPvX	_broadcast_addr;		// Network broadcast address
    IPvX	_peer_addr;			// Peer address (on p2p links)
};

/**
 * @short Virtual Interface class.
 * 
 * Vif holds information about a virtual interface.  A Vif may
 * represent a physical interface, or may represent more abstract
 * entities such as the Discard or Unreachable interface, or a VLAN
 * on a physical interface.
 */
class Vif {
public:
    /**
     * Constructor for a given virtual interface name.
     * 
     * @param vifname string representation of the virtual interface 
     * (e.g., "port 0").
     * @param ifname string representation of associated interface.
     */
    explicit Vif(const string& vifname, const string& ifname = string(""));

#ifdef XORP_USE_USTL
    Vif() { }
#endif
    
    /**
     * Constructor to clone a Vif.
     * 
     * @param vif the virtual interface to clone.
     */
    Vif(const Vif& vif);
    
    /**
     * Destructor
     */
    virtual ~Vif();
    
    /**
     * Convert this Vif from binary form to presentation format.
     * 
     * @return C++ string with the human-readable ASCII representation
     * of the Vif.
     */
    string str() const;

    /**
     * Equality Operator
     * 
     * @param other the right-hand operand to compare against.
     * @return true if the left-hand operand is numerically same as the
     * right-hand operand.
     */
    bool operator==(const Vif& other) const;
    
    /**
     * Get the vif name.
     * 
     * @return a string representation of the vif name.
     */
    const string& name() const { return _name; }

    /**
     * Get the name of the physical interface associated with vif.
     *
     * @return string representation of interface name.
     */
    const string& ifname() const { return _ifname; }

    /**
     * Set the name of the physical interface associated with vif.
     *
     * @param ifname
     */
    void set_ifname(const string& ifname) { _ifname = ifname; }

    /**
     * Get the physical interface index.
     * 
     * @return the physical interface index (if applicable).
     */
    uint32_t pif_index() const { return (_pif_index); }
    
    /**
     * Set the physical interface index.
     * 
     * @param v the value of the physical interface index to set to.
     */
    void set_pif_index(uint32_t v) { _pif_index = v; }
    
    /**
     * Various vif_index related values.
     */
    enum {
	VIF_INDEX_INVALID	= ((uint32_t)~0),
	VIF_INDEX_MAX		= ((uint32_t)~0)
    };
    
    /**
     * Get the virtual interface index.
     * 
     * @return the virtual interface index.
     */
    uint32_t vif_index() const { return (_vif_index); }
    
    /**
     * Set the virtual interface index.
     * 
     * @param v the value of the virtual interface index to set to.
     */
    void set_vif_index(uint32_t v) { _vif_index = v; }

    /**
     * Test if this vif is a PIM Register interface.
     * 
     * @return true if this vif is a PIM Register interface, otherwise false.
     */
    bool	is_pim_register()	const	{ return _is_pim_register; }
    
    /**
     * Test if this vif is a point-to-point interface.
     * 
     * @return true if this vif is a point-to-point interface, otherwise false.
     */
    bool	is_p2p()		const	{ return _is_p2p; }
    
    /**
     * Test if this vif is a loopback interface.
     * 
     * @return true if this vif is a loopback interface, otherwise false.
     */
    bool	is_loopback()		const	{ return _is_loopback; }
    
    /**
     * Test if this vif is a discard interface.
     * 
     * @return true if this vif is a discard interface, otherwise false.
     */
    bool	is_discard()		const	{ return _is_discard; }

    /**
     * Test if this vif is an unreachable interface.
     * 
     * @return true if this vif is an unreachable interface, otherwise false.
     */
    bool	is_unreachable()	const	{ return _is_unreachable; }

    /**
     * Test if this vif is a management interface.
     * 
     * @return true if this vif is a management interface, otherwise false.
     */
    bool	is_management()	const	{ return _is_management; }
    
    /**
     * Test if this vif is multicast capable.
     * 
     * @return true if this vif is multicast capable, otherwise false.
     */
    bool	is_multicast_capable() const { return _is_multicast_capable; }
    
    /**
     * Test if this vif is broadcast capable.
     * 
     * @return true if this vif is broadcast capable, otherwise false.
     */
    bool	is_broadcast_capable() const { return _is_broadcast_capable; }
    
    /**
     * Test if the underlying vif is UP.
     * 
     * An example of an underlying vif is the corresponding interface
     * inside the kernel, or the MFEA interface which a PIM interface
     * matches to.
     * 
     * @return true if the underlying vif is UP (when applicable), otherwise
     * false.
     */
    bool	is_underlying_vif_up() const { return _is_underlying_vif_up; }

    /**
     * Get the MTU of the vif.
     *
     * @return the MTU of the vif.
     */
    uint32_t	mtu() const { return _mtu; }

    /**
     * Set/reset the vif as a PIM Register interface.
     * 
     * @param v if true, then set this vif as a PIM Register interface,
     * otherwise reset it.
     */
    void	set_pim_register(bool v)	{ _is_pim_register = v; }
    
    /**
     * Set/reset the vif as a point-to-point interface.
     * 
     * @param v if true, then set this vif as a point-to-point interface,
     * otherwise reset it.
     */
    void	set_p2p(bool v)			{ _is_p2p = v; }
    
    /**
     * Set/reset the vif as a loopback interface.
     * 
     * @param v if true, then set this vif as a loopback interface,
     * otherwise reset it.
     */
    void	set_loopback(bool v)		{ _is_loopback = v; }
    
    /**
     * Set/reset the vif as a discard interface.
     * 
     * @param v if true, then set this vif as a discard interface,
     * otherwise reset it.
     */
    void	set_discard(bool v)		{ _is_discard = v; }

    /**
     * Set/reset the vif as an unreachable interface.
     * 
     * @param v if true, then set this vif as an unreachable interface,
     * otherwise reset it.
     */
    void	set_unreachable(bool v)		{ _is_unreachable = v; }

    /**
     * Set/reset the vif as a management interface.
     * 
     * @param v if true, then set this vif as a management interface,
     * otherwise reset it.
     */
    void	set_management(bool v)		{ _is_management = v; }
    
    /**
     * Set/reset the vif as multicast capable.
     * 
     * @param v if true, then set this vif as multicast capable,
     * otherwise reset it.
     */
    void	set_multicast_capable(bool v)	{ _is_multicast_capable = v; }
    
    /**
     * Set/reset the vif as broadcast capable.
     * 
     * @param v if true, then set this vif as broadcast capable,
     * otherwise reset it.
     */
    void	set_broadcast_capable(bool v)	{ _is_broadcast_capable = v; }
    
    /**
     * Set/reset the underlying vif status (when applicable).
     * 
     * An example of an underlying vif is the corresponding interface
     * inside the kernel, or the MFEA interface which a PIM interface
     * matches to.
     *
     * @param v if true, then set the underlying vif status as UP,
     * otherwise the underlying vif status is set to DOWN.
     */
    void	set_underlying_vif_up(bool v)	{ _is_underlying_vif_up = v; }

    /**
     * Set the MTU of the vif.
     *
     * @param v the MTU of the vif.
     */
    void	set_mtu(uint32_t v) { _mtu = v; }

    /**
     * Get the list of all addresses for this vif.
     * 
     * @return the list of all addresses for this vif (@ref VifAddr).
     */
    const list<VifAddr>& addr_list() const { return _addr_list; }
    
    /**
     * Get the first vif address.
     * 
     * @return a pointer to the first valid interface address of this vif,
     * or NULL if no addresses.
     */
    const IPvX* addr_ptr() const;
    
    /**
     * Add a VifAddr address to the interface.
     * 
     * @param vif_addr the VifAddr (@ref VifAddr) to add to the list
     * of addresses for this vif.
     * 
     * @return XORP_OK if a new address, otherwise XORP_ERROR.
     */
    int add_address(const VifAddr& vif_addr);
    
    /**
     * Add an IPvX address and all related information to the interface.
     * 
     * @param ipvx_addr the interface address.
     * @param ipvxnet_subnet_addr the subnet address.
     * @param ipvx_broadcast_addr the broadcast address.
     * @param ipvx_peer_addr the peer address.
     * @return XORP_OK if a new address, otherwise XORP_ERROR.
     */
    int add_address(const IPvX& ipvx_addr,
		    const IPvXNet& ipvxnet_subnet_addr,
		    const IPvX& ipvx_broadcast_addr,
		    const IPvX& ipvx_peer_addr);
    
    /**
     * Add an IPvX address to the interface.
     * 
     * @param ipvx_addr the interface address.
     * @return XORP_OK if a new address, otherwise XORP_ERROR.
     */
    int add_address(const IPvX& ipvx_addr);
    
    /**
     * Delete an IPvX address from the interface.
     * 
     * @return XORP_OK on success, otherwise XORP_ERROR.
     */
    int delete_address(const IPvX& ipvx_addr);
    
    /**
     * Find a VifAddr that corresponds to an IPvX address.
     * 
     * @param ipvx_addr the IPvX address to search for.
     * @return a pointer to the VifAddr for address @ref ipvx_addr
     * if found, otherwise NULL.
     */
    VifAddr *find_address(const IPvX& ipvx_addr);

    /**
     * Find a const VifAddr that corresponds to an IPvX address.
     * 
     * @param ipvx_addr the IPvX address to search for.
     * @return a const pointer to the VifAddr for address @ref ipvx_addr
     * if found, otherwise NULL.
     */
    const VifAddr *find_address(const IPvX& ipvx_addr) const;
    
    /**
     * Test if an IPvX address belongs to this vif.
     * 
     * @param ipvx_addr the IPvX address to test whether belongs to this vif.
     * @return true if @ref ipvx_addr belongs to this vif, otherwise false.
     */
    bool is_my_addr(const IPvX& ipvx_addr) const;
    
    /**
     * Test if an VifAddr is belongs to this vif.
     * 
     * @param vif_addr the VifAddr address to test whether belongs to this vif.
     * @return true if @ref vif_addr belongs to this vif, otherwise false.
     */
    bool is_my_vif_addr(const VifAddr& vif_addr) const;
    
    /**
     * Test if a given subnet address is a subset of one of the subnet
     * addresses of this vif.
     * 
     * @param ipvxnet the subnet address to test against.
     * @return true if @ref ipvxnet is a subset of one of the subnet
     * addresses of this vif, otherwise false.
     */
    bool is_same_subnet(const IPvXNet& ipvxnet) const;
    
    /**
     * Test if a given address belongs to one of the subnet addresses
     * of this vif.
     * 
     * @param ipvx_addr the address to test against.
     * @return true if @ref ipvx_addr belongs to one of the subnet addresses
     * of this vif, otherwise false.
     */
    bool is_same_subnet(const IPvX& ipvx_addr) const;
    
    /**
     * Test if a given address belongs to the same point-to-point link
     * as this vif.
     * 
     * @param ipvx_addr the address to test against.
     * @return true if @ref ipvx_addr belongs to the same point-to-point link
     * as this vif, otherwise false.
     */
    bool is_same_p2p(const IPvX& ipvx_addr) const;
    
private:
    string	_name;		// The vif name
    string	_ifname;	// The physical interface name (if applicable)
    uint32_t	_pif_index;	// Physical interface index (if applicable),
				// or 0 if invalid.
    uint32_t	_vif_index;	// Virtual interface index
    bool	_is_pim_register;	// PIM Register vif
    bool	_is_p2p;		// Point-to-point interface
    bool	_is_loopback;		// Loopback interface
    bool	_is_discard;		// Discard interface
    bool	_is_unreachable;	// Unreachable interface
    bool	_is_management;		// Management interface
    bool	_is_multicast_capable;	// Multicast-capable interface
    bool	_is_broadcast_capable;	// Broadcast-capable interface
    bool	_is_underlying_vif_up;	// True if underlying vif is up
    uint32_t	_mtu;			// The MTU of the vif
    
    list<VifAddr> _addr_list;		// The list of addresses for this vif
};

#endif // __LIBXORP_VIF_HH__
