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

// 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/rip/route_entry.cc,v 1.15 2007/02/16 22:47:16 pavlin Exp $"

#include "rip_module.h"

#include "libxorp/ipv4.hh"
#include "libxorp/ipv6.hh"
#include "libxorp/xlog.h"

#include "route_entry.hh"

template <typename A>
inline void
RouteEntry<A>::dissociate()
{
    RouteEntryOrigin<A>* o = _origin;
    _origin = 0;
    if (o) {
	o->dissociate(this);
    }
}

template <typename A>
inline void
RouteEntry<A>::associate(Origin* o)
{
    if (o)
	o->associate(this);
    _origin = o;
}

template <typename A>
RouteEntry<A>::RouteEntry(const Net&	n,
			  const Addr&	nh,
			  uint16_t	cost,
			  Origin*&	o,
			  uint16_t	tag)
    : _net(n), _nh(nh), _cost(cost), _tag(tag), _ref_cnt(0), _filtered(false)
{
    associate(o);
}

template <typename A>
RouteEntry<A>::RouteEntry(const Net&	    n,
			  const Addr&	    nh,
			  uint16_t	    cost,
			  Origin*&	    o,
			  uint16_t	    tag,
			  const PolicyTags& policytags)
    : _net(n), _nh(nh), _cost(cost), _tag(tag), 
      _ref_cnt(0), _policytags(policytags), _filtered(false)
{
    associate(o);
}

template <typename A>
RouteEntry<A>::~RouteEntry()
{
    Origin* o = _origin;
    _origin = 0;
    if (o) {
	o->dissociate(this);
    }
}

template <typename A>
bool
RouteEntry<A>::set_nexthop(const A& nh)
{
    if (nh != _nh) {
	_nh = nh;
	return true;
    }
    return false;
}

template <typename A>
bool
RouteEntry<A>::set_cost(uint16_t cost)
{
    if (cost != _cost) {
	_cost = cost;
	return true;
    }
    return false;
}

template <typename A>
bool
RouteEntry<A>::set_origin(Origin* o)
{
    if (o != _origin) {
	dissociate();
	associate(o);
	return true;
    }
    return false;
}

template <typename A>
bool
RouteEntry<A>::set_tag(uint16_t tag)
{
    if (tag != _tag) {
	_tag = tag;
	return true;
    }
    return false;
}


template <typename A>
bool
RouteEntry<A>::set_policytags(const PolicyTags& ptags)
{
    if (ptags != _policytags) {
	_policytags = ptags;
	return true;
    }
    return false;
}


/**
 * A comparitor for the purposes of sorting containers of RouteEntry objects.
 * It examines the data rather than using the address of pointers.  The
 * latter approach makes testing difficult on different platforms since the
 * tests may inadvertantly make assumptions about the memory layout.  The
 * comparison is arbitrary, it just has to be consistent and reversible.
 *
 * IFF speed proves to be an issue, RouteEntry can be changed to be an element
 * in an intrusive linked list that has a sentinel embedded in the
 * RouteEntryOrigin.
 */
template <typename A>
struct NetCmp {
    bool operator() (const IPNet<A>& l, const IPNet<A>& r) const
    {
	if (l.prefix_len() < r.prefix_len())
	    return true;
	if (l.prefix_len() > r.prefix_len())
	    return false;
	return l.masked_addr() < r.masked_addr();
    }
};

// ----------------------------------------------------------------------------
// RouteEntryOrigin<A>::RouteEntryStore and related
//
// RouteEntryStore is a private class that is used by Route Origin's to store
// their associated routes.
//

#include <map>

template <typename A>
struct RouteEntryOrigin<A>::RouteEntryStore {
public:
    typedef map<IPNet<A>, RouteEntry<A>*, NetCmp<A> > Container;
    Container routes;
};


// ----------------------------------------------------------------------------
// RouteEntryOrigin

template <typename A>
RouteEntryOrigin<A>::RouteEntryOrigin(bool is_rib_origin)
    : _is_rib_origin(is_rib_origin)
{
    _rtstore = new RouteEntryStore();
}

template <typename A>
RouteEntryOrigin<A>::~RouteEntryOrigin()
{
    // XXX store should be empty
    XLOG_ASSERT(_rtstore->routes.empty());
    delete _rtstore;
}

template <typename A>
bool
RouteEntryOrigin<A>::associate(Route* r)
{
    XLOG_ASSERT(r != 0);
    if (_rtstore->routes.find(r->net()) != _rtstore->routes.end()) {
	XLOG_FATAL("entry already exists");
	return false;
    }
    _rtstore->routes.insert(typename
			    RouteEntryStore::Container::value_type(r->net(), r));
    return true;
}

template <typename A>
bool
RouteEntryOrigin<A>::dissociate(Route* r)
{
    typename RouteEntryStore::Container::iterator
	i = _rtstore->routes.find(r->net());

    if (i == _rtstore->routes.end()) {
	XLOG_FATAL("entry does not exist");
	return false;
    }
    _rtstore->routes.erase(i);
    return true;
}

template <typename A>
uint32_t
RouteEntryOrigin<A>::route_count() const
{
    return static_cast<uint32_t>(_rtstore->routes.size());
}

template <typename A>
void
RouteEntryOrigin<A>::clear()
{
    typename RouteEntryStore::Container::iterator
	i = _rtstore->routes.begin();
    while (i != _rtstore->routes.end()) {
	Route* r = i->second;
	delete r;
	i = _rtstore->routes.begin();
    }
}

template <typename A>
void
RouteEntryOrigin<A>::dump_routes(vector<const Route*>& routes) const
{
    typename RouteEntryStore::Container::const_iterator
	i = _rtstore->routes.begin();
    typename RouteEntryStore::Container::const_iterator
	end = _rtstore->routes.end();

    while (i != end) {
	routes.push_back(i->second);
	++i;
    }
}

template <typename A>
RouteEntry<A>*
RouteEntryOrigin<A>::find_route(const Net& n) const
{
    typename RouteEntryStore::Container::const_iterator
	i = _rtstore->routes.find(n);
    if (i == _rtstore->routes.end())
	return 0;
    return i->second;
}


// ----------------------------------------------------------------------------
// Instantiations

#ifdef INSTANTIATE_IPV4
template class RouteEntryOrigin<IPv4>;
template class RouteEntry<IPv4>;
#endif

#ifdef INSTANTIATE_IPV6
template class RouteEntryOrigin<IPv6>;
template class RouteEntry<IPv6>;
#endif


syntax highlighted by Code2HTML, v. 0.9.1