// -*- c-basic-offset: 4; tab-width: 8; indent-tabs-mode: t -*-
// Copyright (c) 2001-2007 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.
#ident "$XORP: xorp/rib/vifmanager.cc,v 1.44 2007/02/16 22:47:11 pavlin Exp $"
#include "rib_module.h"
#include "libxorp/xorp.h"
#include "libxorp/xlog.h"
#include "libxorp/debug.h"
#include "libxorp/ipvx.hh"
#include "libxorp/status_codes.h"
#include "libxipc/xrl_router.hh"
#include "rib_manager.hh"
#include "vifmanager.hh"
VifManager::VifManager(XrlRouter& xrl_router,
EventLoop& eventloop,
RibManager* rib_manager,
const string& fea_target)
: _xrl_router(xrl_router),
_eventloop(eventloop),
_rib_manager(rib_manager),
_ifmgr(eventloop, fea_target.c_str(), xrl_router.finder_address(),
xrl_router.finder_port()),
_startup_requests_n(0),
_shutdown_requests_n(0)
{
enable(); // XXX: by default the VifManager is always enabled
//
// Set myself as an observer when the node status changes
//
set_observer(this);
_ifmgr.set_observer(this);
_ifmgr.attach_hint_observer(this);
}
VifManager::~VifManager()
{
//
// Unset myself as an observer when the node status changes
//
unset_observer(this);
stop();
_ifmgr.detach_hint_observer(this);
_ifmgr.unset_observer(this);
}
/**
* Start operation.
*
* Start the process of registering with the FEA, etc.
* After the startup operations are completed,
* @ref VifManager::final_start() is called internally
* to complete the job.
*
* @return XORP_OK on success, otherwise XORP_ERROR.
*/
int
VifManager::start()
{
if (is_up() || is_pending_up())
return (XORP_OK);
enable(); // XXX: by default the VifManager is always enabled
if (ProtoState::pending_start() < 0)
return (XORP_ERROR);
//
// Startup the interface manager
//
if (ifmgr_startup() != true) {
ServiceBase::set_status(SERVICE_FAILED);
return (XORP_ERROR);
}
return (XORP_OK);
}
/**
* Completely start the node operation.
*
* This method should be called internally after @ref VifManager::start()
* to complete the job.
*
* @return XORP_OK on success, otherwise XORP_ERROR.
*/
int
VifManager::final_start()
{
#if 0 // TODO: XXX: PAVPAVPAV
if (! is_pending_up())
return (XORP_ERROR);
#endif
if (ProtoState::start() < 0) {
ProtoState::stop();
return (XORP_ERROR);
}
return (XORP_OK);
}
/**
* Stop operation.
*
* Gracefully stop operation.
* After the shutdown operations are completed,
* @ref VifManager::final_stop() is called internally
* to complete the job.
*
* @return XORP_OK on success, otherwise XORP_ERROR.
*/
int
VifManager::stop()
{
if (is_down())
return (XORP_OK);
if (! (is_up() || is_pending_up() || is_pending_down()))
return (XORP_ERROR);
if (ProtoState::pending_stop() < 0)
return (XORP_ERROR);
//
// Shutdown the interface manager
//
if (ifmgr_shutdown() != true) {
ServiceBase::set_status(SERVICE_FAILED);
return (XORP_ERROR);
}
return (XORP_OK);
}
/**
* Completely stop the node operation.
*
* This method should be called internally after @ref VifManager::stop()
* to complete the job.
*
* @return XORP_OK on success, otherwise XORP_ERROR.
*/
int
VifManager::final_stop()
{
#if 0
if (! (is_up() || is_pending_up() || is_pending_down()))
return (XORP_ERROR);
#endif
if (ProtoState::stop() < 0)
return (XORP_ERROR);
// Clear the old state
_iftree.clear();
_old_iftree.clear();
return (XORP_OK);
}
void
VifManager::status_change(ServiceBase* service,
ServiceStatus old_status,
ServiceStatus new_status)
{
if (service == this) {
// My own status has changed
if ((old_status == SERVICE_STARTING)
&& (new_status == SERVICE_RUNNING)) {
// The startup process has completed
if (final_start() < 0) {
XLOG_ERROR("Cannot complete the startup process; "
"current state is %s",
ProtoState::state_str().c_str());
return;
}
return;
}
if ((old_status == SERVICE_SHUTTING_DOWN)
&& (new_status == SERVICE_SHUTDOWN)) {
// The shutdown process has completed
final_stop();
return;
}
//
// TODO: check if there was an error
//
return;
}
if (service == ifmgr_mirror_service_base()) {
if ((old_status == SERVICE_SHUTTING_DOWN)
&& (new_status == SERVICE_SHUTDOWN)) {
decr_shutdown_requests_n();
}
}
}
void
VifManager::update_status()
{
//
// Test if the startup process has completed
//
if (ServiceBase::status() == SERVICE_STARTING) {
if (_startup_requests_n > 0)
return;
// The startup process has completed
ServiceBase::set_status(SERVICE_RUNNING);
return;
}
//
// Test if the shutdown process has completed
//
if (ServiceBase::status() == SERVICE_SHUTTING_DOWN) {
if (_shutdown_requests_n > 0)
return;
// The shutdown process has completed
ServiceBase::set_status(SERVICE_SHUTDOWN);
return;
}
//
// Test if we have failed
//
if (ServiceBase::status() == SERVICE_FAILED) {
return;
}
}
bool
VifManager::ifmgr_startup()
{
bool ret_value;
// TODO: XXX: we should startup the ifmgr only if it hasn't started yet
incr_startup_requests_n();
ret_value = _ifmgr.startup();
//
// XXX: when the startup is completed, IfMgrHintObserver::tree_complete()
// will be called.
//
return ret_value;
}
bool
VifManager::ifmgr_shutdown()
{
bool ret_value;
incr_shutdown_requests_n();
ret_value = _ifmgr.shutdown();
//
// XXX: when the shutdown is completed, VifManager::status_change()
// will be called.
//
return ret_value;
}
void
VifManager::tree_complete()
{
//
// XXX: we use same actions when the tree is completed or updates are made
//
updates_made();
decr_startup_requests_n();
}
void
VifManager::updates_made()
{
string error_msg;
IfMgrIfTree::IfMap::const_iterator ifmgr_iface_iter;
IfMgrIfAtom::VifMap::const_iterator ifmgr_vif_iter;
IfMgrVifAtom::V4Map::const_iterator a4_iter;
IfMgrVifAtom::V6Map::const_iterator a6_iter;
//
// Update the local copy of the interface tree
//
_old_iftree = _iftree;
_iftree = ifmgr_iftree();
//
// Remove vifs that don't exist anymore
//
for (ifmgr_iface_iter = _old_iftree.ifs().begin();
ifmgr_iface_iter != _old_iftree.ifs().end();
++ifmgr_iface_iter) {
const IfMgrIfAtom& ifmgr_iface = ifmgr_iface_iter->second;
const string& ifmgr_iface_name = ifmgr_iface.name();
if (_iftree.find_vif(ifmgr_iface_name, ifmgr_iface_name) == NULL) {
if (_rib_manager->delete_vif(ifmgr_iface_name, error_msg)
!= XORP_OK) {
XLOG_ERROR("Cannot delete vif %s from the set of configured "
"vifs: %s",
ifmgr_iface_name.c_str(), error_msg.c_str());
}
}
}
//
// Add new vifs, update existing ones and remove old addresses
//
for (ifmgr_iface_iter = _iftree.ifs().begin();
ifmgr_iface_iter != _iftree.ifs().end();
++ifmgr_iface_iter) {
const IfMgrIfAtom& ifmgr_iface = ifmgr_iface_iter->second;
const string& ifmgr_iface_name = ifmgr_iface.name();
for (ifmgr_vif_iter = ifmgr_iface.vifs().begin();
ifmgr_vif_iter != ifmgr_iface.vifs().end();
++ifmgr_vif_iter) {
const IfMgrVifAtom& ifmgr_vif = ifmgr_vif_iter->second;
const string& ifmgr_vif_name = ifmgr_vif.name();
const IfMgrVifAtom* old_ifmgr_vif_ptr;
old_ifmgr_vif_ptr = _old_iftree.find_vif(ifmgr_iface_name,
ifmgr_vif_name);
// The vif to add (eventually)
Vif vif(ifmgr_vif_name);
//
// Set the pif_index
//
if (old_ifmgr_vif_ptr == NULL)
vif.set_pif_index(ifmgr_vif.pif_index());
//
// Update or set the vif flags
// XXX: discard property needs to be inherited from
// the parent interface, once it has been marshaled.
//
bool is_up = ifmgr_iface.enabled() && ifmgr_vif.enabled();
is_up &= (! ifmgr_iface.no_carrier()); // XXX: the link state
if (old_ifmgr_vif_ptr != NULL) {
if (_rib_manager->set_vif_flags(ifmgr_vif_name,
ifmgr_vif.p2p_capable(),
ifmgr_vif.loopback(),
ifmgr_vif.multicast_capable(),
ifmgr_vif.broadcast_capable(),
is_up,
ifmgr_iface.mtu_bytes(),
error_msg)
!= XORP_OK) {
XLOG_ERROR("Cannot update the flags for vif %s: %s",
ifmgr_vif_name.c_str(), error_msg.c_str());
}
} else {
vif.set_ifname(ifmgr_iface_name);
vif.set_p2p(ifmgr_vif.p2p_capable());
vif.set_loopback(ifmgr_vif.loopback());
vif.set_multicast_capable(ifmgr_vif.multicast_capable());
vif.set_broadcast_capable(ifmgr_vif.broadcast_capable());
vif.set_underlying_vif_up(is_up);
vif.set_mtu(ifmgr_iface.mtu_bytes());
}
//
// Delete vif addresses that don't exist anymore
//
if (old_ifmgr_vif_ptr != NULL) {
for (a4_iter = old_ifmgr_vif_ptr->ipv4addrs().begin();
a4_iter != old_ifmgr_vif_ptr->ipv4addrs().end();
++a4_iter) {
const IfMgrIPv4Atom& a4 = a4_iter->second;
const IPv4& addr = a4.addr();
if (_iftree.find_addr(ifmgr_iface_name,
ifmgr_vif_name,
addr)
== NULL) {
if (_rib_manager->delete_vif_address(ifmgr_vif_name,
addr,
error_msg)
!= XORP_OK) {
XLOG_ERROR("Cannot delete address %s "
"for vif %s: %s",
addr.str().c_str(),
ifmgr_vif_name.c_str(),
error_msg.c_str());
}
}
}
for (a6_iter = old_ifmgr_vif_ptr->ipv6addrs().begin();
a6_iter != old_ifmgr_vif_ptr->ipv6addrs().end();
++a6_iter) {
const IfMgrIPv6Atom& a6 = a6_iter->second;
const IPv6& addr = a6.addr();
if (_iftree.find_addr(ifmgr_iface_name,
ifmgr_vif_name,
addr)
== NULL) {
if (_rib_manager->delete_vif_address(ifmgr_vif_name,
addr,
error_msg)
!= XORP_OK) {
XLOG_ERROR("Cannot delete address %s "
"for vif %s: %s",
addr.str().c_str(),
ifmgr_vif_name.c_str(),
error_msg.c_str());
}
}
}
}
//
// Add a new vif
//
if (old_ifmgr_vif_ptr == NULL) {
if (_rib_manager->new_vif(ifmgr_vif_name, vif, error_msg)
!= XORP_OK) {
XLOG_ERROR("Cannot add vif %s to the set of configured "
"vifs: %s",
ifmgr_vif_name.c_str(), error_msg.c_str());
}
}
}
}
//
// Add new vif addresses, and update existing ones
//
for (ifmgr_iface_iter = _iftree.ifs().begin();
ifmgr_iface_iter != _iftree.ifs().end();
++ifmgr_iface_iter) {
const IfMgrIfAtom& ifmgr_iface = ifmgr_iface_iter->second;
const string& ifmgr_iface_name = ifmgr_iface.name();
for (ifmgr_vif_iter = ifmgr_iface.vifs().begin();
ifmgr_vif_iter != ifmgr_iface.vifs().end();
++ifmgr_vif_iter) {
const IfMgrVifAtom& ifmgr_vif = ifmgr_vif_iter->second;
const string& ifmgr_vif_name = ifmgr_vif.name();
const IfMgrVifAtom* old_ifmgr_vif_ptr;
old_ifmgr_vif_ptr = _old_iftree.find_vif(ifmgr_iface_name,
ifmgr_vif_name);
for (a4_iter = ifmgr_vif.ipv4addrs().begin();
a4_iter != ifmgr_vif.ipv4addrs().end();
++a4_iter) {
const IfMgrIPv4Atom& a4 = a4_iter->second;
const IPv4& addr = a4.addr();
const IfMgrIPv4Atom* old_a4_ptr = NULL;
if (old_ifmgr_vif_ptr != NULL)
old_a4_ptr = old_ifmgr_vif_ptr->find_addr(addr);
if ((old_a4_ptr != NULL) && (*old_a4_ptr == a4))
continue; // Nothing changed
IPv4Net subnet_addr(addr, a4.prefix_len());
IPv4 broadcast_addr(IPv4::ZERO());
IPv4 peer_addr(IPv4::ZERO());
if (a4.has_broadcast())
broadcast_addr = a4.broadcast_addr();
if (a4.has_endpoint())
peer_addr = a4.endpoint_addr();
if (old_a4_ptr != NULL) {
// Delete the old address so it can be replaced
if (_rib_manager->delete_vif_address(ifmgr_vif_name,
addr,
error_msg)
!= XORP_OK) {
XLOG_ERROR("Cannot delete address %s "
"for vif %s: %s",
addr.str().c_str(),
ifmgr_vif_name.c_str(),
error_msg.c_str());
}
}
if (_rib_manager->add_vif_address(ifmgr_vif_name,
addr,
subnet_addr,
broadcast_addr,
peer_addr,
error_msg)
!= XORP_OK) {
XLOG_ERROR("Cannot add address %s to vif %s from "
"the set of configured vifs: %s",
cstring(addr), ifmgr_vif_name.c_str(),
error_msg.c_str());
}
}
for (a6_iter = ifmgr_vif.ipv6addrs().begin();
a6_iter != ifmgr_vif.ipv6addrs().end();
++a6_iter) {
const IfMgrIPv6Atom& a6 = a6_iter->second;
const IPv6& addr = a6.addr();
const IfMgrIPv6Atom* old_a6_ptr = NULL;
if (old_ifmgr_vif_ptr != NULL)
old_a6_ptr = old_ifmgr_vif_ptr->find_addr(addr);
if ((old_a6_ptr != NULL) && (*old_a6_ptr == a6))
continue; // Nothing changed
IPv6Net subnet_addr(addr, a6.prefix_len());
IPv6 peer_addr(IPv6::ZERO());
if (a6.has_endpoint())
peer_addr = a6.endpoint_addr();
if (old_a6_ptr != NULL) {
// Delete the old address so it can be replaced
if (_rib_manager->delete_vif_address(ifmgr_vif_name,
addr,
error_msg)
!= XORP_OK) {
XLOG_ERROR("Cannot delete address %s "
"for vif %s: %s",
addr.str().c_str(),
ifmgr_vif_name.c_str(),
error_msg.c_str());
}
}
if (_rib_manager->add_vif_address(ifmgr_vif_name,
addr,
subnet_addr,
peer_addr,
error_msg)
!= XORP_OK) {
XLOG_ERROR("Cannot add address %s to vif %s from "
"the set of configured vifs: %s",
cstring(addr), ifmgr_vif_name.c_str(),
error_msg.c_str());
}
}
}
}
}
void
VifManager::incr_startup_requests_n()
{
_startup_requests_n++;
XLOG_ASSERT(_startup_requests_n > 0);
}
void
VifManager::decr_startup_requests_n()
{
XLOG_ASSERT(_startup_requests_n > 0);
_startup_requests_n--;
update_status();
}
void
VifManager::incr_shutdown_requests_n()
{
_shutdown_requests_n++;
XLOG_ASSERT(_shutdown_requests_n > 0);
}
void
VifManager::decr_shutdown_requests_n()
{
XLOG_ASSERT(_shutdown_requests_n > 0);
_shutdown_requests_n--;
update_status();
}
syntax highlighted by Code2HTML, v. 0.9.1