// -*- 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/fea/iftree.cc,v 1.37 2007/02/16 22:45:44 pavlin Exp $"
#include "fea_module.h"
#include "libxorp/xorp.h"
#include "libxorp/xlog.h"
#include "libxorp/debug.h"
#include "libxorp/c_format.hh"
#include "iftree.hh"
/* ------------------------------------------------------------------------- */
/* Misc */
static inline const char* true_false(bool b)
{
return b ? "true" : "false";
}
/* ------------------------------------------------------------------------- */
/* IfTreeItem code */
string
IfTreeItem::str() const
{
struct {
State st;
const char* desc;
} t[] = { { CREATED, "CREATED" },
{ DELETED, "DELETED" },
{ CHANGED, "CHANGED" }
};
string r;
for (size_t i = 0; i < sizeof(t) / sizeof(t[0]); i++) {
if ((_st & t[i].st) == 0) continue;
if (r.empty() == false) r += ",";
r += t[i].desc;
}
return r;
}
/* ------------------------------------------------------------------------- */
/* IfTree code */
void
IfTree::clear()
{
_ifs.clear();
}
bool
IfTree::add_if(const string& ifname)
{
IfMap::iterator ii = get_if(ifname);
if (ii != ifs().end()) {
ii->second.mark(CREATED);
return true;
}
_ifs.insert(IfMap::value_type(ifname, IfTreeInterface(ifname)));
return true;
}
IfTree::IfMap::iterator
IfTree::get_if(uint32_t ifindex)
{
IfTree::IfMap::iterator ii;
for (ii = _ifs.begin(); ii != _ifs.end(); ++ii) {
if (ii->second.pif_index() == ifindex)
break;
}
return ii;
}
IfTree::IfMap::const_iterator
IfTree::get_if(uint32_t ifindex) const
{
IfTree::IfMap::const_iterator ii;
for (ii = _ifs.begin(); ii != _ifs.end(); ++ii) {
if (ii->second.pif_index() == ifindex)
break;
}
return ii;
}
bool
IfTree::remove_if(const string& ifname)
{
IfMap::iterator ii = get_if(ifname);
if (ii == ifs().end())
return false;
ii->second.mark(DELETED);
return true;
}
/**
* 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
IfTree::update_if(const IfTreeInterface& other_iface)
{
IfTree::IfMap::iterator ii;
IfTreeInterface::VifMap::iterator vi;
IfTreeInterface::VifMap::const_iterator ov;
//
// Add the interface if we don't have it already
//
ii = get_if(other_iface.ifname());
if (ii == ifs().end()) {
add_if(other_iface.ifname());
ii = get_if(other_iface.ifname());
}
IfTreeInterface& this_iface = ii->second;
//
// Update the interface state
//
if (! this_iface.is_same_state(other_iface))
this_iface.copy_state(other_iface);
//
// Update existing vifs and addresses
//
for (vi = this_iface.vifs().begin();
vi != this_iface.vifs().end();
++vi) {
IfTreeVif& this_vif = vi->second;
ov = other_iface.get_vif(this_vif.vifname());
if (ov == other_iface.vifs().end()) {
this_vif.mark(DELETED);
continue;
}
const IfTreeVif& other_vif = ov->second;
if (! this_vif.is_same_state(this_vif))
this_vif.copy_state(other_vif);
IfTreeVif::V4Map::iterator ai4;
for (ai4 = this_vif.v4addrs().begin();
ai4 != this_vif.v4addrs().end();
++ai4) {
IfTreeVif::V4Map::const_iterator oa4;
oa4 = other_vif.get_addr(ai4->second.addr());
if (oa4 == other_vif.v4addrs().end()) {
ai4->second.mark(DELETED);
continue;
}
if (! ai4->second.is_same_state(oa4->second))
ai4->second.copy_state(oa4->second);
}
IfTreeVif::V6Map::iterator ai6;
for (ai6 = this_vif.v6addrs().begin();
ai6 != this_vif.v6addrs().end();
++ai6) {
IfTreeVif::V6Map::const_iterator oa6;
oa6 = other_vif.get_addr(ai6->second.addr());
if (oa6 == other_vif.v6addrs().end()) {
ai6->second.mark(DELETED);
continue;
}
if (! ai6->second.is_same_state(oa6->second))
ai6->second.copy_state(oa6->second);
}
}
//
// Add the new vifs and addresses
//
for (ov = other_iface.vifs().begin();
ov != other_iface.vifs().end();
++ov) {
const IfTreeVif& other_vif = ov->second;
if (this_iface.get_vif(other_vif.vifname()) != this_iface.vifs().end())
continue; // The vif was already updated
// Add the vif
this_iface.add_vif(other_vif.vifname());
vi = this_iface.get_vif(other_vif.vifname());
IfTreeVif& this_vif = vi->second;
this_vif.copy_state(other_vif);
// Add the IPv4 addresses
IfTreeVif::V4Map::const_iterator oa4;
for (oa4 = other_vif.v4addrs().begin();
oa4 != other_vif.v4addrs().end();
++oa4) {
IfTreeVif::V4Map::iterator ai4;
ai4 = this_vif.get_addr(oa4->second.addr());
if (ai4 != this_vif.v4addrs().end())
continue; // The address was already updated
// Add the address
this_vif.add_addr(oa4->second.addr());
ai4 = this_vif.get_addr(oa4->second.addr());
ai4->second.copy_state(oa4->second);
}
// Add the IPv6 addresses
IfTreeVif::V6Map::const_iterator oa6;
for (oa6 = other_vif.v6addrs().begin();
oa6 != other_vif.v6addrs().end();
++oa6) {
IfTreeVif::V6Map::iterator ai6;
ai6 = this_vif.get_addr(oa6->second.addr());
if (ai6 != this_vif.v6addrs().end())
continue; // The address was already updated
// Add the address
this_vif.add_addr(oa6->second.addr());
ai6 = this_vif.get_addr(oa6->second.addr());
ai6->second.copy_state(oa6->second);
}
}
return true;
}
void
IfTree::finalize_state()
{
IfMap::iterator ii = _ifs.begin();
while (ii != _ifs.end()) {
//
// If interface is marked as deleted, delete it.
//
if (ii->second.is_marked(DELETED)) {
_ifs.erase(ii++);
continue;
}
//
// Call finalize_state on interfaces that remain
//
ii->second.finalize_state();
++ii;
}
set_state(NO_CHANGE);
}
string
IfTree::str() const
{
string r;
for (IfMap::const_iterator ii = ifs().begin(); ii != ifs().end(); ++ii) {
const IfTreeInterface& fi = ii->second;
r += fi.str() + string("\n");
for (IfTreeInterface::VifMap::const_iterator vi = fi.vifs().begin();
vi != fi.vifs().end(); ++vi) {
const IfTreeVif& fv = vi->second;
r += string(" ") + fv.str() + string("\n");
for (IfTreeVif::V4Map::const_iterator ai = fv.v4addrs().begin();
ai != fv.v4addrs().end(); ++ai) {
const IfTreeAddr4& a = ai->second;
r += string(" ") + a.str() + string("\n");
}
for (IfTreeVif::V6Map::const_iterator ai = fv.v6addrs().begin();
ai != fv.v6addrs().end(); ++ai) {
const IfTreeAddr6& a = ai->second;
r += string(" ") + a.str() + string("\n");
}
}
}
return r;
}
/**
* 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&
IfTree::align_with(const IfTree& other)
{
IfTree::IfMap::iterator ii;
for (ii = ifs().begin(); ii != ifs().end(); ++ii) {
const string& ifname = ii->second.ifname();
IfTree::IfMap::const_iterator oi = other.get_if(ifname);
bool flipped = ii->second.flipped();
if (! ii->second.enabled()) {
if ((oi != other.ifs().end())
&& (! ii->second.is_same_state(oi->second))) {
ii->second.copy_state(oi->second);
ii->second.set_enabled(false);
ii->second.set_flipped(flipped);
}
continue;
}
if (oi == other.ifs().end()) {
//
// Mark local interface for deletion, not present in other,
// unless the local interface is marked as "soft" or
// "discard_emulated".
//
if (! (ii->second.is_soft() || ii->second.is_discard_emulated()))
ii->second.mark(DELETED);
continue;
} else {
if (! ii->second.is_same_state(oi->second)) {
ii->second.copy_state(oi->second);
ii->second.set_flipped(flipped);
}
}
IfTreeInterface::VifMap::iterator vi;
for (vi = ii->second.vifs().begin();
vi != ii->second.vifs().end(); ++vi) {
const string& vifname = vi->second.vifname();
IfTreeInterface::VifMap::const_iterator ov =
oi->second.get_vif(vifname);
if (! vi->second.enabled()) {
if ((ov != oi->second.vifs().end())
&& (! vi->second.is_same_state(ov->second))) {
vi->second.copy_state(ov->second);
vi->second.set_enabled(false);
}
continue;
}
if (ov == oi->second.vifs().end()) {
vi->second.mark(DELETED);
continue;
} else {
if (! vi->second.is_same_state(ov->second))
vi->second.copy_state(ov->second);
}
IfTreeVif::V4Map::iterator ai4;
for (ai4 = vi->second.v4addrs().begin();
ai4 != vi->second.v4addrs().end(); ++ai4) {
IfTreeVif::V4Map::const_iterator oa4 =
ov->second.get_addr(ai4->second.addr());
if (! ai4->second.enabled()) {
if ((oa4 != ov->second.v4addrs().end())
&& (! ai4->second.is_same_state(oa4->second))) {
ai4->second.copy_state(oa4->second);
ai4->second.set_enabled(false);
}
continue;
}
if (oa4 == ov->second.v4addrs().end()) {
ai4->second.mark(DELETED);
} else {
if (! ai4->second.is_same_state(oa4->second))
ai4->second.copy_state(oa4->second);
}
}
IfTreeVif::V6Map::iterator ai6;
for (ai6 = vi->second.v6addrs().begin();
ai6 != vi->second.v6addrs().end(); ++ai6) {
IfTreeVif::V6Map::const_iterator oa6 =
ov->second.get_addr(ai6->second.addr());
if (! ai6->second.enabled()) {
if ((oa6 != ov->second.v6addrs().end())
&& (! ai6->second.is_same_state(oa6->second))) {
ai6->second.copy_state(oa6->second);
ai6->second.set_enabled(false);
}
continue;
}
if (oa6 == ov->second.v6addrs().end()) {
ai6->second.mark(DELETED);
} else {
if (! ai6->second.is_same_state(oa6->second))
ai6->second.copy_state(oa6->second);
}
}
}
}
return *this;
}
/**
* 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 are 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&
IfTree::prepare_replacement_state(const IfTree& other)
{
IfTree::IfMap::iterator ii;
IfTree::IfMap::const_iterator oi;
//
// Mark all entries in the local tree as created
//
for (ii = ifs().begin(); ii != ifs().end(); ++ii) {
ii->second.mark(CREATED);
IfTreeInterface::VifMap::iterator vi;
for (vi = ii->second.vifs().begin();
vi != ii->second.vifs().end(); ++vi) {
vi->second.mark(CREATED);
IfTreeVif::V4Map::iterator ai4;
for (ai4 = vi->second.v4addrs().begin();
ai4 != vi->second.v4addrs().end(); ++ai4) {
ai4->second.mark(CREATED);
}
IfTreeVif::V6Map::iterator ai6;
for (ai6 = vi->second.v6addrs().begin();
ai6 != vi->second.v6addrs().end(); ++ai6) {
ai6->second.mark(CREATED);
}
}
}
for (oi = other.ifs().begin(); oi != other.ifs().end(); ++oi) {
if (! oi->second.enabled())
continue; // XXX: ignore disabled state
const string& ifname = oi->second.ifname();
ii = get_if(ifname);
if (ii == ifs().end()) {
//
// Add local interface and mark it for deletion.
//
// Mark local interface for deletion, not present in other,
// unless the local interface is marked as "soft" or
// "discard_emulated".
//
if (! (oi->second.is_soft() || oi->second.is_discard_emulated())) {
add_if(ifname);
ii = get_if(ifname);
XLOG_ASSERT(ii != ifs().end());
ii->second.copy_state(oi->second);
ii->second.mark(DELETED);
}
}
IfTreeInterface::VifMap::const_iterator ov;
for (ov = oi->second.vifs().begin();
ov != oi->second.vifs().end(); ++ov) {
if (! ov->second.enabled())
continue; // XXX: ignore disabled state
const string& vifname = ov->second.vifname();
IfTreeInterface::VifMap::iterator vi =
ii->second.get_vif(vifname);
if (vi == ii->second.vifs().end()) {
//
// Add local vif and mark it for deletion.
//
ii->second.add_vif(vifname);
vi = ii->second.get_vif(vifname);
XLOG_ASSERT(vi != ii->second.vifs().end());
vi->second.copy_state(ov->second);
vi->second.mark(DELETED);
}
IfTreeVif::V4Map::const_iterator oa4;
for (oa4 = ov->second.v4addrs().begin();
oa4 != ov->second.v4addrs().end(); ++oa4) {
if (! oa4->second.enabled())
continue; // XXX: ignore disabled state
IfTreeVif::V4Map::iterator ai4 =
vi->second.get_addr(oa4->second.addr());
if (ai4 == vi->second.v4addrs().end()) {
//
// Add local IPv4 address and mark it for deletion.
//
vi->second.add_addr(oa4->second.addr());
ai4 = vi->second.get_addr(oa4->second.addr());
XLOG_ASSERT(ai4 != vi->second.v4addrs().end());
ai4->second.copy_state(oa4->second);
ai4->second.mark(DELETED);
}
}
IfTreeVif::V6Map::const_iterator oa6;
for (oa6 = ov->second.v6addrs().begin();
oa6 != ov->second.v6addrs().end(); ++oa6) {
if (! oa6->second.enabled())
continue; // XXX: ignore disabled state
IfTreeVif::V6Map::iterator ai6 =
vi->second.get_addr(oa6->second.addr());
if (ai6 == vi->second.v6addrs().end()) {
//
// Add local IPv6 address and mark it for deletion.
//
vi->second.add_addr(oa6->second.addr());
ai6 = vi->second.get_addr(oa6->second.addr());
XLOG_ASSERT(ai6 != vi->second.v6addrs().end());
ai6->second.copy_state(oa6->second);
ai6->second.mark(DELETED);
}
}
}
}
return *this;
}
/**
* 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&
IfTree::prune_bogus_deleted_state(const IfTree& old_iftree)
{
IfTree::IfMap::iterator ii;
ii = _ifs.begin();
while (ii != _ifs.end()) {
const string& ifname = ii->second.ifname();
if (! ii->second.is_marked(DELETED)) {
++ii;
continue;
}
IfTree::IfMap::const_iterator oi;
oi = old_iftree.get_if(ifname);
if (oi == old_iftree.ifs().end()) {
// Remove this item from the local tree
_ifs.erase(ii++);
continue;
}
IfTreeInterface::VifMap::iterator vi;
vi = ii->second.vifs().begin();
while (vi != ii->second.vifs().end()) {
const string& vifname = vi->second.vifname();
if (! vi->second.is_marked(DELETED)) {
++vi;
continue;
}
IfTreeInterface::VifMap::const_iterator ov;
ov = oi->second.get_vif(vifname);
if (ov == oi->second.vifs().end()) {
// Remove this item from the local tree
ii->second.vifs().erase(vi++);
continue;
}
IfTreeVif::V4Map::iterator ai4;
ai4 = vi->second.v4addrs().begin();
while (ai4 != vi->second.v4addrs().end()) {
if (! ai4->second.is_marked(DELETED)) {
++ai4;
continue;
}
IfTreeVif::V4Map::const_iterator oa4;
oa4 = ov->second.get_addr(ai4->second.addr());
if (oa4 == ov->second.v4addrs().end()) {
// Remove this item from the local tree
vi->second.v4addrs().erase(ai4++);
continue;
}
++ai4;
}
IfTreeVif::V6Map::iterator ai6;
ai6 = vi->second.v6addrs().begin();
while (ai6 != vi->second.v6addrs().end()) {
if (! ai6->second.is_marked(DELETED)) {
++ai6;
continue;
}
IfTreeVif::V6Map::const_iterator oa6;
oa6 = ov->second.get_addr(ai6->second.addr());
if (oa6 == ov->second.v6addrs().end()) {
// Remove this item from the local tree
vi->second.v6addrs().erase(ai6++);
continue;
}
++ai6;
}
++vi;
}
++ii;
}
return *this;
}
/**
* 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 state
* 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&
IfTree::track_live_config_state(const IfTree& other)
{
IfTree::IfMap::iterator ii;
IfTree::IfMap::const_iterator oi;
for (oi = other.ifs().begin(); oi != other.ifs().end(); ++oi) {
const string& ifname = oi->second.ifname();
ii = get_if(ifname);
if (ii == ifs().end())
continue;
//
// Update the "no_carrier" flag
//
if (ii->second.no_carrier() != oi->second.no_carrier()) {
ii->second.set_no_carrier(oi->second.no_carrier());
}
}
return *this;
}
/* ------------------------------------------------------------------------- */
/* IfTreeInterface code */
IfTreeInterface::IfTreeInterface(const string& ifname)
: IfTreeItem(), _ifname(ifname), _pif_index(0),
_enabled(false), _discard(false), _is_discard_emulated(false),
_mtu(0), _no_carrier(false), _flipped(false), _if_flags(0)
{}
bool
IfTreeInterface::add_vif(const string& vifname)
{
VifMap::iterator vi = get_vif(vifname);
if (vi != _vifs.end()) {
vi->second.mark(CREATED);
return true;
}
_vifs.insert(VifMap::value_type(vifname, IfTreeVif(name(), vifname)));
return true;
}
bool
IfTreeInterface::remove_vif(const string& vifname)
{
VifMap::iterator vi = get_vif(vifname);
if (vi == _vifs.end())
return false;
vi->second.mark(DELETED);
return true;
}
void
IfTreeInterface::finalize_state()
{
VifMap::iterator vi = _vifs.begin();
while (vi != _vifs.end()) {
//
// If interface is marked as deleted, delete it.
//
if (vi->second.is_marked(DELETED)) {
_vifs.erase(vi++);
continue;
}
//
// Call finalize_state on vifs that remain
//
vi->second.finalize_state();
++vi;
}
set_state(NO_CHANGE);
}
string
IfTreeInterface::str() const
{
return c_format("Interface %s { enabled := %s } "
"{ mtu := %u } { mac := %s } {no_carrier = %s} "
"{ flipped := %s } { flags := %u }",
_ifname.c_str(),
true_false(_enabled),
XORP_UINT_CAST(_mtu),
_mac.str().c_str(),
true_false(_no_carrier),
true_false(_flipped),
XORP_UINT_CAST(_if_flags))
+ string(" ")
+ IfTreeItem::str();
}
/* ------------------------------------------------------------------------- */
/* IfTreeVif code */
IfTreeVif::IfTreeVif(const string& ifname, const string& vifname)
: IfTreeItem(), _ifname(ifname), _vifname(vifname),
_pif_index(0), _enabled(false),
_broadcast(false), _loopback(false), _point_to_point(false),
_multicast(false)
{}
bool
IfTreeVif::add_addr(const IPv4& v4addr)
{
V4Map::iterator ai = get_addr(v4addr);
if (ai != v4addrs().end()) {
ai->second.mark(CREATED);
return true;
}
_v4addrs.insert(V4Map::value_type(v4addr, IfTreeAddr4(v4addr)));
return true;
}
bool
IfTreeVif::remove_addr(const IPv4& v4addr)
{
V4Map::iterator ai = get_addr(v4addr);
if (ai == v4addrs().end())
return false;
ai->second.mark(DELETED);
return true;
}
bool
IfTreeVif::add_addr(const IPv6& v6addr)
{
V6Map::iterator ai = get_addr(v6addr);
if (ai != v6addrs().end()) {
ai->second.mark(CREATED);
return true;
}
_v6addrs.insert(V6Map::value_type(v6addr, IfTreeAddr6(v6addr)));
return true;
}
bool
IfTreeVif::remove_addr(const IPv6& v6addr)
{
V6Map::iterator ai = get_addr(v6addr);
if (ai == v6addrs().end())
return false;
ai->second.mark(DELETED);
return true;
}
void
IfTreeVif::finalize_state()
{
for (V4Map::iterator ai = _v4addrs.begin(); ai != _v4addrs.end(); ) {
//
// If address is marked as deleted, delete it.
//
if (ai->second.is_marked(DELETED)) {
_v4addrs.erase(ai++);
continue;
}
//
// Call finalize_state on addresses that remain
//
ai->second.finalize_state();
++ai;
}
for (V6Map::iterator ai = _v6addrs.begin(); ai != _v6addrs.end(); ) {
//
// If address is marked as deleted, delete it.
//
if (ai->second.is_marked(DELETED)) {
_v6addrs.erase(ai++);
continue;
}
//
// Call finalize_state on interfaces that remain
//
ai->second.finalize_state();
++ai;
}
set_state(NO_CHANGE);
}
string
IfTreeVif::str() const
{
return c_format("VIF %s { enabled := %s } { broadcast := %s } "
"{ loopback := %s } { point_to_point := %s } "
"{ multicast := %s } ",
_vifname.c_str(), true_false(_enabled),
true_false(_broadcast), true_false(_loopback),
true_false(_point_to_point), true_false(_multicast))
+ string(" ") + IfTreeItem::str();
}
/* ------------------------------------------------------------------------- */
/* IfTreeAddr4 code */
bool
IfTreeAddr4::set_prefix_len(uint32_t prefix_len)
{
if (prefix_len > IPv4::addr_bitlen())
return false;
_prefix_len = prefix_len;
mark(CHANGED);
return true;
}
void
IfTreeAddr4::set_bcast(const IPv4& baddr)
{
_oaddr = baddr;
mark(CHANGED);
}
IPv4
IfTreeAddr4::bcast() const
{
if (broadcast())
return _oaddr;
return IPv4::ZERO();
}
void
IfTreeAddr4::set_endpoint(const IPv4& oaddr)
{
_oaddr = oaddr;
mark(CHANGED);
}
IPv4
IfTreeAddr4::endpoint() const
{
if (point_to_point())
return _oaddr;
return IPv4::ZERO();
}
void
IfTreeAddr4::finalize_state()
{
set_state(NO_CHANGE);
}
string
IfTreeAddr4::str() const
{
string r = c_format("V4Addr %s { enabled := %s } { broadcast := %s } "
"{ loopback := %s } { point_to_point := %s } "
"{ multicast := %s } "
"{ prefix_len := %u }",
_addr.str().c_str(), true_false(_enabled),
true_false(_broadcast), true_false(_loopback),
true_false(_point_to_point), true_false(_multicast),
XORP_UINT_CAST(_prefix_len));
if (_point_to_point)
r += c_format(" { endpoint := %s }", _oaddr.str().c_str());
if (_broadcast)
r += c_format(" { broadcast := %s }", _oaddr.str().c_str());
r += string(" ") + IfTreeItem::str();
return r;
}
/* ------------------------------------------------------------------------- */
/* IfTreeAddr6 code */
bool
IfTreeAddr6::set_prefix_len(uint32_t prefix_len)
{
if (prefix_len > IPv6::addr_bitlen())
return false;
_prefix_len = prefix_len;
mark(CHANGED);
return true;
}
void
IfTreeAddr6::set_endpoint(const IPv6& oaddr)
{
_oaddr = oaddr;
mark(CHANGED);
}
IPv6
IfTreeAddr6::endpoint() const
{
if (point_to_point())
return _oaddr;
return IPv6::ZERO();
}
void
IfTreeAddr6::finalize_state()
{
set_state(NO_CHANGE);
}
string
IfTreeAddr6::str() const
{
string r = c_format("V6Addr %s { enabled := %s } "
"{ loopback := %s } { point_to_point := %s } "
"{ multicast := %s } "
"{ prefix_len := %u }",
_addr.str().c_str(), true_false(_enabled),
true_false(_loopback),
true_false(_point_to_point), true_false(_multicast),
XORP_UINT_CAST(_prefix_len));
if (_point_to_point)
r += c_format(" { endpoint := %s }", _oaddr.str().c_str());
r += string(" ") + IfTreeItem::str();
return r;
}
syntax highlighted by Code2HTML, v. 0.9.1