Source: ../../libproto/proto_node.hh
|
|
|
|
// -*- c-basic-offset: 4; tab-width: 8; indent-tabs-mode: t -*-
// Copyright (c) 2001-2003 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/libproto/proto_node.hh,v 1.4 2003/03/10 23:20:20 hodson Exp $
#ifndef __LIBPROTO_PROTO_NODE_HH__
#define __LIBPROTO_PROTO_NODE_HH__
#include <map>
#include <vector>
#include "libxorp/xorp.h"
#include "libxorp/callback.hh"
#include "proto_unit.hh"
//
// Protocol node generic functionality
//
//
// Constants definitions
//
//
// Structures/classes, typedefs and macros
//
class EventLoop;
class IPvX;
class Vif;
/**
* @short Base class for a protocol node.
*/
template<class V>
class ProtoNode : public ProtoUnit {
public:
/**
* Constructor for a given address family, module ID, and event loop.
*
* @param init_family the address family (AF_INET or AF_INET6 for
* IPv4 and IPv6 respectively).
* @param init_module_id the module ID X_MODULE_* (@ref x_module_id).
* @param init_event_loop the event loop to use.
*/
ProtoNode(int init_family, x_module_id init_module_id,
EventLoop& init_event_loop)
: ProtoUnit(init_family, init_module_id),
_event_loop(init_event_loop),
_is_vif_setup_completed(false) {}
/**
* Destructor
*/
virtual ~ProtoNode() {
// TODO: free vifs (after they are added, etc.
}
#if 0 // TODO: add it later to start/stop all vifs, etc??
int start();
int stop();
void enable();
void disable();
#endif
/**
* Map a vif name to a vif index.
*
* @param vif_name the vif name to map to a vif index.
* @return the virtual interface index for vif name @ref vif_name.
*/
inline uint16_t vif_name2vif_index(const string& vif_name) const;
/**
* Find an unused vif index.
*
* @return the smallest unused vif index if there is one available,
* otherwise return @ref Vif::VIF_INDEX_INVALID.
*/
inline uint16_t find_unused_vif_index() const;
/**
* Find a virtual interface for a given name.
*
* @param name the name to search for.
* @return the virtual interface with name @ref name if found,
* otherwise NULL.
*/
inline V *vif_find_by_name(const string& name) const;
/**
* Find a virtual interface for a given address.
*
* @param ipaddr_test the address to search for.
* @return the virtual interface with address @ref ipaddr_test if found,
* otherwise NULL.
*/
inline V *vif_find_by_addr(const IPvX& ipaddr_test) const;
/**
* Find a virtual interface for a given physical interface index.
*
* @param pif_index the physical interface index to search for.
* @return the virtual interface with physical interface index @ref
* pif_index if found, otherwise NULL.
*/
inline V *vif_find_by_pif_index(uint16_t pif_index) const;
/**
* Find a virtual interface for a given virtual interface index.
*
* @param vif_index the virtual interface index to search for.
* @return the vvirtual interface with virtual interface index @ref
* vif_index if found, otherwise NULL.
*/
inline V *vif_find_by_vif_index(uint16_t vif_index) const;
/**
* Find a virtual interface that is directly connected to the given
* address.
*
* @param ipaddr_test the address to search by.
* @return the virtual interface that is directly connected to
* address @ref ipaddr_test if found, otherwise NULL.
*/
inline V *vif_find_direct(const IPvX& ipaddr_test) const;
/**
* Test if an address is directly connected to one of my virtual
* interfaces.
*
* @param ipaddr_test the address to test.
* @return true if @ref ipaddr_test is directly connected to one of
* my virtual interfaces, otherwise false.
*/
bool is_directly_connected(const IPvX& ipaddr_test) const {
return (vif_find_direct(ipaddr_test) != NULL);
}
/**
* Test if an address belongs to one of my virtual interfaces.
*
* @param ipaddr_test the address to test.
* @return true if @ref ipaddr_test belongs to one of my virtual
* interfaces, otherwise false.
*/
bool is_my_addr(const IPvX& ipaddr_test) const {
return (vif_find_by_addr(ipaddr_test) != NULL);
}
/**
* Add a virtual interface.
*
* @param vif a pointer to the virtual interface to add.
* @return XORP_OK on success, otherwise XORP_ERROR.
*/
inline int add_vif(V *vif);
/**
* Delete a virtual interface.
*
* Note: the @ref vif itself is not deleted, only its place in the
* array of protocol vifs.
*
* @param vif a pointer to the virtual interface to delete.
* @return XORP_OK on success, otherwise XORP_ERROR.
*/
inline int delete_vif(const V *vif);
/**
* Get the array of pointers to the virtual interfaces.
*
* @return the array of pointers to the virtual interfaces.
*/
vector<V *>& proto_vifs() { return (_proto_vifs); }
/**
* Get the maximum number of vifs.
*
* Note: the interfaces that are not configured or are down are
* also included.
*
* @return the maximum number of vifs we can have.
*/
uint16_t maxvifs() const { return (_proto_vifs.size()); }
/**
* Get the event loop this node is added to.
*
* @return the event loop this node is added to.
*/
EventLoop& event_loop() { return (_event_loop); }
/**
* Test if the vif setup is completed.
*
* @return true if the vif setup is completed, otherwise false.
*/
bool is_vif_setup_completed() const { return (_is_vif_setup_completed); }
/**
* Set/reset the flag that indicates whether the vif setup is completed.
*
* @param v if true, set the flag that the vif setup is completed,
* otherwise reset it.
*/
void set_vif_setup_completed(bool v) { _is_vif_setup_completed = v; }
/**
* Receive a protocol message.
*
* This is a pure virtual function, and it must be implemented
* by the particular protocol node class that inherits this base class.
*
* @param src_module_instance_name the module instance name of the
* module-origin of the message.
*
* @param src_module_id the module ID (@ref x_module_id) of the
* module-origin of the message.
*
* @param vif_index the vif index of the interface used to receive this
* message.
*
* @param src the source address of the message.
*
* @param dst the destination address of the message.
*
* @param ip_ttl the IP TTL (Time To Live) of the message. If it has
* a negative value, it should be ignored.
*
* @param ip_tos the IP TOS (Type of Service) of the message. If it has
* a negative value, it should be ignored.
*
* @param router_alert_bool if true, the ROUTER_ALERT IP option for the IP
* packet of the incoming message was set.
*
* @param rcvbuf the data buffer with the received message.
*
* @param rcvlen the data length in @ref rcvbuf.
*
* @return XORP_OK on success, otherwise XORP_ERROR.
*/
virtual int proto_recv(const string& src_module_instance_name,
x_module_id src_module_id,
uint16_t vif_index,
const IPvX& src,
const IPvX& dst,
int ip_ttl,
int ip_tos,
bool router_alert_bool,
const uint8_t *rcvbuf,
size_t rcvlen) = 0;
/**
* Send a protocol message.
*
* This is a pure virtual function, and it must be implemented
* by the particular protocol node class that inherits this base class.
*
* @param dst_module_instance_name the module instance name of the
* module-recepient of the message.
*
* @param dst_module_id the module ID (@ref x_module_id) of the
* module-recepient of the message.
*
* @param vif_index the vif index of the interface to send this message.
*
* @param src the source address of the message.
*
* @param dst the destination address of the message.
*
* @param ip_ttl the IP TTL of the message. If it has a negative value,
* the TTL will be set by the lower layers.
*
* @param ip_tos the IP TOS of the message. If it has a negative value,
* the TOS will be set by the lower layers.
*
* @param router_alert_bool if true, set the ROUTER_ALERT IP option for
* the IP packet of the outgoung message.
*
* @param sndbuf the data buffer with the outgoing message.
*
* @param sndlen the data length in @ref sndbuf.
*
* @return XORP_OK on success, otherwise XORP_ERROR.
*/
virtual int proto_send(const string& dst_module_instance_name,
x_module_id dst_module_id,
uint16_t vif_index,
const IPvX& src,
const IPvX& dst,
int ip_ttl,
int ip_tos,
bool router_alert_bool,
const uint8_t *sndbuf,
size_t sndlen) = 0;
/**
* Receive a signal message.
*
* This is a pure virtual function, and it must be implemented
* by the particular protocol node class that inherits this base class.
*
* @param src_module_instance_name the module instance name of the
* module-origin of the message.
*
* @param src_module_id the module ID (@ref x_module_id) of the
* module-origin of the message.
*
* @param message_type the message type. The particular values are
* specific for the origin and recepient of this signal message.
*
* @param vif_index the vif index of the related interface
* (message-specific relation).
*
* @param src the source address of the message. The exact meaning of
* this address is message-specific.
*
* @param dst the destination address of the message. The exact meaning of
* this address is message-specific.
*
* @param rcvbuf the data buffer with the additional information in
* the message.
* @param rcvlen the data length in @ref rcvbuf.
*
* @return XORP_OK on success, otherwise XORP_ERROR.
*/
virtual int signal_message_recv(const string& src_module_instance_name,
x_module_id src_module_id,
int message_type,
uint16_t vif_index,
const IPvX& src,
const IPvX& dst,
const uint8_t *rcvbuf,
size_t rcvlen) = 0;
/**
* Send a signal message.
*
* This is a pure virtual function, and it must be implemented
* by the particular protocol node class that inherits this base class.
*
* @param dst_module_instance_name the module instance name of the
* module-recepient of the message.
*
* @param dst_module_id the module ID (@ref x_module_id) of the
* module-recepient of the message.
*
* @param message_type the message type. The particular values are
* specific for the origin and recepient of this signal message.
*
* @param vif_index the vif index of the related interface
* (message-specific relation).
*
* @param src the source address of the message. The exact meaning of
* this address is message-specific.
*
* @param dst the destination address of the message. The exact meaning of
* this address is message-specific.
*
* @param sndbuf the data buffer with the outgoing message.
*
* @param sndlen the data length in @ref sndbuf.
*
* @return XORP_OK on success, otherwise XORP_ERROR.
*/
virtual int signal_message_send(const string& dst_module_instance_name,
x_module_id dst_module_id,
int message_type,
uint16_t vif_index,
const IPvX& src,
const IPvX& dst,
const uint8_t *sndbuf,
size_t sndlen) = 0;
private:
// TODO: add vifs, etc
vector<V *> _proto_vifs; // The array with all protocol vifs
EventLoop& _event_loop; // The event loop to use
map<string, uint16_t> _vif_name2vif_index_map;
bool _is_vif_setup_completed; // True if the vifs are setup
};
//
// Deferred definitions
//
template<class V>
inline uint16_t
ProtoNode<V>::vif_name2vif_index(const string& vif_name) const
{
map<string, uint16_t>::const_iterator iter;
iter = find(_vif_name2vif_index_map.find(vif_name));
if (iter != _vif_name2vif_index_map.end())
return (iter->second);
return (Vif::VIF_INDEX_INVALID);
}
template<class V>
inline uint16_t
ProtoNode<V>::find_unused_vif_index() const
{
for (uint16_t i = 0; i < _proto_vifs.size(); i++) {
if (_proto_vifs[i] == NULL)
return (i);
}
if (maxvifs() + 1 >= Vif::VIF_INDEX_MAX)
return (Vif::VIF_INDEX_INVALID);
return (maxvifs());
}
template<class V>
inline V *
ProtoNode<V>::vif_find_by_name(const string& name) const
{
typename vector<V *>::const_iterator iter;
for (iter = _proto_vifs.begin(); iter != _proto_vifs.end(); ++iter) {
V *vif = *iter;
if (vif->name() == name)
return (vif);
}
return (NULL);
}
template<class V>
inline V *
ProtoNode<V>::vif_find_by_addr(const IPvX& ipaddr_test) const
{
typename vector<V *>::const_iterator iter;
for (iter = _proto_vifs.begin(); iter != _proto_vifs.end(); ++iter) {
V *vif = *iter;
if (vif->is_my_addr(ipaddr_test))
return (vif);
}
return (NULL);
}
template<class V>
inline V *
ProtoNode<V>::vif_find_by_pif_index(uint16_t pif_index) const
{
typename vector<V *>::const_iterator iter;
for (iter = _proto_vifs.begin(); iter != _proto_vifs.end(); ++iter) {
V *vif = *iter;
if (vif->pif_index() == pif_index)
return (vif);
}
return (NULL);
}
template<class V>
inline V *
ProtoNode<V>::vif_find_by_vif_index(uint16_t vif_index) const
{
if (vif_index < _proto_vifs.size()) {
// XXX: if vif_index becomes signed, we must check (vif_index >= 0)
return (_proto_vifs[vif_index]);
}
return (NULL);
}
template<class V>
inline V *
ProtoNode<V>::vif_find_direct(const IPvX& ipaddr_test) const
{
typename vector<V *>::const_iterator iter;
for (iter = _proto_vifs.begin(); iter != _proto_vifs.end(); ++iter) {
V *vif = *iter;
if (vif->is_directly_connected(ipaddr_test))
return (vif);
}
return (NULL);
}
template<class V>
inline int
ProtoNode<V>::add_vif(V *vif)
{
// XXX: vif setup is not completed, if we are trying to add a vif
_is_vif_setup_completed = false;
if (vif == NULL) {
XLOG_ERROR("Cannot add NULL vif");
return (XORP_ERROR);
}
if (vif_find_by_name(vif->name()) != NULL) {
XLOG_ERROR("Cannot add vif %s: already exist",
vif->name().c_str());
return (XORP_ERROR);
}
if (vif_find_by_vif_index(vif->vif_index()) != NULL) {
XLOG_ERROR("Cannot add vif %s with vif_index = %d: "
"already exist vif with such vif_index",
vif->name().c_str(), vif->vif_index());
return (XORP_ERROR);
}
// XXX: we should check for the pif_index as well, but on older
// systems the kernel doesn't assign pif_index to the interfaces
//
// Add enough empty entries for the new vif
//
while (vif->vif_index() >= maxvifs()) {
_proto_vifs.push_back(NULL);
}
XLOG_ASSERT(_proto_vifs[vif->vif_index()] == NULL);
//
// Add the new vif
//
_proto_vifs[vif->vif_index()] = vif;
// Add the entry to the vif_name2vif_index map
_vif_name2vif_index_map.insert(
pair<string, uint16_t>(vif->name(), vif->vif_index()));
return (XORP_OK);
}
template<class V>
inline int
ProtoNode<V>::delete_vif(const V *vif)
{
// XXX: vif setup is not completed, if we are trying to delete a vif
_is_vif_setup_completed = false;
if (vif == NULL) {
XLOG_ERROR("Cannot delete NULL vif");
return (XORP_ERROR);
}
if (vif_find_by_name(vif->name()) != vif) {
XLOG_ERROR("Cannot delete vif %s: inconsistent data pointers",
vif->name().c_str());
return (XORP_ERROR);
}
if (vif_find_by_vif_index(vif->vif_index()) != vif) {
XLOG_ERROR("Cannot delete vif %s with vif_index = %d: "
"inconsistent data pointers",
vif->name().c_str(), vif->vif_index());
return (XORP_ERROR);
}
XLOG_ASSERT(vif->vif_index() < maxvifs());
XLOG_ASSERT(_proto_vifs[vif->vif_index()] == vif);
_proto_vifs[vif->vif_index()] = NULL;
//
// Remove unused vif pointers from the back of the vif array
//
while (_proto_vifs.size()) {
size_t i = _proto_vifs.size() - 1;
if (_proto_vifs[i] != NULL)
break;
_proto_vifs.pop_back();
}
// Remove the entry from the vif_name2vif_index map
map<string, uint16_t>::iterator iter;
iter = _vif_name2vif_index_map.find(vif->name());
XLOG_ASSERT(iter != _vif_name2vif_index_map.end());
_vif_name2vif_index_map.erase(iter);
return (XORP_OK);
}
//
// Global variables
//
//
// Global functions prototypes
//
#endif // __LIBPROTO_PROTO_NODE_HH__
Generated by: pavlin on possum.icir.org on Mon Mar 10 19:34:51 2003, using kdoc 2.0a54+XORP. |