Source: ../../bgp/subnet_route.hh
|
|
|
|
// -*- c-basic-offset: 4; tab-width: 8; indent-tabs-mode: t -*-
// vim:set sts=4 ts=8:
// Copyright (c) 2001-2009 XORP, Inc.
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License, Version 2, June
// 1991 as published by the Free Software Foundation. Redistribution
// and/or modification of this program under the terms of any other
// version of the GNU 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 General Public License, Version 2, a copy of which can be
// found in the XORP LICENSE.gpl file.
//
// XORP Inc, 2953 Bunker Hill Lane, Suite 204, Santa Clara, CA 95054, USA;
// http://xorp.net
// $XORP: xorp/bgp/subnet_route.hh,v 1.29 2009/01/05 18:30:43 jtc Exp $
#ifndef __BGP_SUBNET_ROUTE_HH__
#define __BGP_SUBNET_ROUTE_HH__
#include "path_attribute.hh"
#include "attribute_manager.hh"
#include "libxorp/xorp.h"
#include "libxorp/ipv4net.hh"
#include "libxorp/ipv6net.hh"
#include "policy/backend/policytags.hh"
#include "policy/backend/policy_filter.hh"
#define SRF_IN_USE 0x00000001
#define SRF_WINNER 0x00000002
#define SRF_FILTERED 0x00000004
#define SRF_DELETED 0x00000008
#define SRF_NH_RESOLVED 0x00000010
#define SRF_AGGR_BRIEF_MODE 0x00000080
#define SRF_AGGR_PREFLEN_MASK 0x0000ff00
#define SRF_REFCOUNT 0xffff0000
// Aggregation flags
// XXX Marko any better ideas where to put those?
#define SR_AGGR_IGNORE 0xff
#define SR_AGGR_IBGP_ONLY 0xe0
#define SR_AGGR_EBGP_AGGREGATE 0xd0
#define SR_AGGR_EBGP_NOT_AGGREGATED 0xd1
#define SR_AGGR_EBGP_WAS_AGGREGATED 0xd2
//Defining paranoid emables some additional checks to ensure we don't
//try to reuse deleted data, or follow an obsolete parent_route
//pointer.
template<class A>
class SubnetRouteRef;
template<class A>
class SubnetRouteConstRef;
class RouteMetaData {
public:
RouteMetaData(const RouteMetaData& metadata);
RouteMetaData();
~RouteMetaData() {
// prevent accidental reuse after deletion
_flags = 0xffffffff;
}
/**
* @return whether or not this route is in use. "in use" here
* does not mean the route won the decision process, but rather
* that it was at least a contender for decision, and was not
* filtered in the incoming filter bank.
*/
inline bool in_use() const {return (_flags & SRF_IN_USE) != 0;}
/**
* Record whether or not this route is in use. "in use" here
* does not mean the route won the decision process, but rather
* that it was at least a contender for decision, and was not
* filtered in the incoming filter bank.
*
* @param used true if the route is "in use".
*/
void set_in_use(bool used) {
if (used) {
_flags |= SRF_IN_USE;
} else {
_flags &= ~SRF_IN_USE;
}
}
/**
* returns true if the route was chosen by the routing decision
* process as the winning route for this subnet.
*
* is_winner should NOT be called by anything other than the
* DecisionTable because caching means that it may not return the
* right answer anywhere else
*/
inline bool is_winner() const {return (_flags & SRF_WINNER) != 0;}
/**
* when a route is chosen by the routing decision process as the
* winning route for this subnet, set_is_winner should be called
* to record this fact and to record the igp_metric at the time
* the route was chosen.
*
* set_is_winner should NOT be called by anything other than the
* DecisionTable because caching means that it may not return the
* right answer anywhere else
*/
void set_is_winner(uint32_t igp_metric) {
_flags |= SRF_WINNER;
_igp_metric = igp_metric;
}
/**
* when a route fails to be chosen by the routing decision process as the
* winning route for this subnet, set_is_not_winner should be called
* to record this fact.
*/
inline void set_is_not_winner() {
_flags &= ~SRF_WINNER;
}
/**
* record whether or not a route's nexthop resolved
*/
void set_nexthop_resolved(bool resolvable) {
if (resolvable) {
_flags |= SRF_NH_RESOLVED;
} else {
_flags &= ~SRF_NH_RESOLVED;
}
}
/**
* did the route's nexthop resolve when it was passed through the
* NextHop resolver table.
*/
inline bool nexthop_resolved() const {
return (_flags & SRF_NH_RESOLVED) != 0;
}
/**
* is_filtered returns true if the route was filtered out by the
* incoming filter bank, false otherwise. As such it only makes
* sense calling this on routes that are stored in the RibIn.
*/
inline bool is_filtered() const {return (_flags & SRF_FILTERED) != 0;}
/**
* set_filtered record whether or not the route was filtered out
* by the incoming filter bank. As such it only
* makes sense calling this on routes that are stored in the
* RibIn.
*
* @param filtered true if the route was filtered, false otherwise.
*/
void set_filtered(bool filtered) {
if (filtered) {
_flags |= SRF_FILTERED;
} else {
_flags &= ~SRF_FILTERED;
}
}
/**
* is_deleted returns true if the route has already been deleted
* (but the class instance representing it has not been because
* it's reference count is non-zero)
*/
inline bool is_deleted() const {return (_flags & SRF_DELETED) != 0;}
inline void set_deleted() {_flags |= SRF_DELETED;}
/**
* @returns the IGP routing protocol metric that applied when the
* route won the decision process. If the route has not won, this
* value is undefined.
*/
inline uint32_t igp_metric() const {return _igp_metric;}
inline void set_igp_metric(uint32_t igp_metric) {
_igp_metric = igp_metric;
}
inline void dont_aggregate() {
_flags |= SRF_AGGR_PREFLEN_MASK;
}
inline uint16_t refcount() const {
return (_flags & SRF_REFCOUNT) >> 16;
}
//set our reference count to one (our own self-reference)
//and clear the deleted flag
inline void reset_flags() {
_flags ^= (_flags & (SRF_REFCOUNT | SRF_DELETED));
}
/**
* @return policy tags associated with route.
*/
inline const PolicyTags& policytags() const {
return _policytags;
}
/**
* Replaced policy tags of route.
*
* @param tags new policy tags for route.
*/
inline void set_policytags(const PolicyTags& tags) {
_policytags = tags;
}
inline const RefPf& policyfilter(uint32_t i) const {
return _pfilter[i];
}
inline void set_policyfilter(uint32_t i, const RefPf& pf) {
_pfilter[i] = pf;
}
/**
* Set the "brief" mode flag on an candidate for aggregation.
*/
void set_aggr_brief_mode() {
_flags |= SRF_AGGR_BRIEF_MODE;
}
/**
* Clear the "brief" mode flag on an candidate for aggregation.
*/
void clear_aggr_brief_mode() {
_flags &= ~SRF_AGGR_BRIEF_MODE;
}
/**
* Read the "brief" aggregation mode flag.
*/
bool aggr_brief_mode() const {
return (_flags & SRF_AGGR_BRIEF_MODE);
}
/**
* Set the target prefix length on an candidate for aggregation.
* The field is also used for storing aggregation markers.
*
* @param preflen prefix length of the requested aggregate route.
*/
void set_aggr_prefix_len(uint32_t preflen) {
_flags = (_flags & ~SRF_AGGR_PREFLEN_MASK) |
((preflen << 8) & SRF_AGGR_PREFLEN_MASK);
}
/**
* Read the aggregation prefix length marker.
* The field is also used for storing aggregation markers.
*/
uint32_t aggr_prefix_len() const {
return (_flags & SRF_AGGR_PREFLEN_MASK) >> 8;
}
bool bump_refcount(int delta) {
XLOG_ASSERT(delta == 1 || delta == -1);
uint16_t refs = refcount();
if (delta == 1) {
XLOG_ASSERT(refs < 0xffff);
} else {
XLOG_ASSERT(refs > 0);
}
refs += delta;
//re-insert the new ref count
_flags = (_flags ^ (_flags&SRF_REFCOUNT)) | (refs << 16);
//handle delayed deletion
if ((refs==0) && ((_flags & SRF_DELETED) != 0)) {
return true;
}
return false;
}
private:
/**
* Flag definitions:
*
* SRF_IN_USE indicates whether this route is currently
* used for anything. The route might not be used if it wasn't
* chosen by the BGP decision mechanism, or if a downstream filter
* caused a modified version of this route to be installed in a
* cache table
*
* SRF_WINNER indicates that the route won the decision process.
*
* SRF_FILTERED indicates that the route was filtered downstream.
* Currently this is only used for RIB-IN routes that are filtered
* in the inbound filter bank
*
* SRF_REFCOUNT (16 bits) maintains a reference count of the number
* of objects depending on this SubnetRoute instance. Deletion
* will be delayed until the reference count reaches zero
*/
uint32_t _flags;
/**
* If the route is a winner (SRF_WINNER is set), then
* DecisionTable will fill in the IGP metric that was used in
* deciding the route was a winner
*/
uint32_t _igp_metric;
PolicyTags _policytags;
RefPf _pfilter[3];
};
/**
* @short SubnetRoute holds a BGP routing table entry.
*
* SubnetRoute is the basic class used to hold a BGP routing table
* entry in BGP's internal representation. It's templated so the same
* code can be used to hold IPv4 or IPv6 routes - their representation
* is essentially the same internally, even though they're encoded
* differently on the wire by the BGP protocol. A route essentially
* consists of the subnet (address and prefix) referred to by the
* route, a BGP path attribute list, and some metadata for our own
* use. When a route update from BGP comes it, it is split into
* multiple subnet routes, one for each NLRI (IPv4) or MP_REACH (IPv6)
* attribute. SubnetRoute is also the principle way routing
* information is passed around internally in our BGP implementation.
*
* SubnetRoute is reference-counted - delete should NOT normally be
* called directly on a SubnetRoute; instead unref should be called,
* which will decrement the reference count, and delete the instance
* if the reference count has reached zero.
*/
template<class A>
class SubnetRoute
{
friend class SubnetRouteRef<A>;
friend class SubnetRouteConstRef<A>;
public:
/**
* @short SubnetRoute copy constructor
*/
SubnetRoute(const SubnetRoute<A>& route_to_clone);
/**
* @short SubnetRoute constructor
*
* @param net the subnet (address and prefix) this route refers to.
* @param attributes pointer to the path attribute list associated with * this route.
* @param parent_route the SubnetRoute that this route was derived
* from. For example, if a filter takes one SubnetRoute and
* generates a modified version, the parent_route of the new one
* should point to the original. If this is set to non-NULL, care
* must be taken to ensure the original route is never deleted
* before the derived route.
*/
SubnetRoute(const IPNet<A> &net,
PAListRef<A> attributes,
const SubnetRoute<A>* parent_route);
/**
* @short SubnetRoute constructor
*
* @param net the subnet (address and prefix) this route refers to.
* @param attributes pointer to the path attribute list associated with * this route.
* @param parent_route the SubnetRoute that this route was derived
* from. For example, if a filter takes one SubnetRoute and
* generates a modified version, the parent_route of the new one
* should point to the original. If this is set to non-NULL, care
* must be taken to ensure the original route is never deleted
* before the derived route.
* @param igp_metric the IGP routing protocol metric to reach the
* nexthop obtained from the RIB.
*/
SubnetRoute(const IPNet<A> &net,
PAListRef<A> attributes,
const SubnetRoute<A>* parent_route,
uint32_t igp_metric);
/**
* @short Equality comparison for SubnetRoutes
*
* Equality comparison for SubnetRoutes. Only the subnet and
* attributes are compared, not the metadata such as flags,
* igp_metric, etc
*
* @param them Route to be compared against.
*/
bool operator==(const SubnetRoute<A>& them) const;
/**
* @return the subnet this route refers to.
*/
const IPNet<A>& net() const {return _net;}
#if 0
/**
* @return the address of the nexthop for this route.
*/
// remove this because we shouldn't be pulling attributes directly
// out of the stored version - use a FastPathAttributeList
// instead.
const A& nexthop() const {return _attributes.nexthop();}
#endif
/**
* @return a pointer to the path attribute list for this route.
*/
PAListRef<A> attributes() const {return _attributes;}
/**
* @return whether or not this route is in use. "in use" here
* does not mean the route won the decision process, but rather
* that it was at least a contender for decision, and was not
* filtered in the incoming filter bank.
*/
bool in_use() const {return _metadata.in_use();}
/**
* Record whether or not this route is in use. "in use" here
* does not mean the route won the decision process, but rather
* that it was at least a contender for decision, and was not
* filtered in the incoming filter bank.
*
* @param used true if the route is "in use".
*/
void set_in_use(bool used) const;
/**
* returns true if the route was chosen by the routing decision
* process as the winning route for this subnet.
*
* is_winner should NOT be called by anything other than the
* DecisionTable because caching means that it may not return the
* right answer anywhere else
*/
bool is_winner() const {return _metadata.is_winner();}
/**
* when a route is chosen by the routing decision process as the
* winning route for this subnet, set_is_winner should be called
* to record this fact and to record the igp_metric at the time
* the route was chosen.
*
* set_is_winner should NOT be called by anything other than the
* DecisionTable because caching means that it may not return the
* right answer anywhere else
*/
void set_is_winner(uint32_t igp_metric) const;
/**
* when a route fails to be chosen by the routing decision process as the
* winning route for this subnet, set_is_not_winner should be called
* to record this fact.
*/
void set_is_not_winner() const;
/**
* record whether or not a route's nexthop resolved
*/
void set_nexthop_resolved(bool resolved) const;
/**
* did the route's nexthop resolve when it was passed through the
* NextHop resolver table.
*/
bool nexthop_resolved() const {return _metadata.nexthop_resolved();}
/**
* is_filtered returns true if the route was filtered out by the
* incoming filter bank, false otherwise. As such it only makes
* sense calling this on routes that are stored in the RibIn.
*/
bool is_filtered() const {return _metadata.is_filtered();}
/**
* set_filtered record whether or not the route was filtered out
* by the incoming filter bank. As such it only
* makes sense calling this on routes that are stored in the
* RibIn.
*
* @param filtered true if the route was filtered, false otherwise.
*/
void set_filtered(bool filtered) const;
/**
* is_deleted returns true if the route has already been deleted
* (but the class instance representing it has not been because
* it's reference count is non-zero)
*/
bool is_deleted() const {return _metadata.is_deleted();}
/**
* @returns a string representation of the route for debugging purposes
*/
string str() const;
/**
* @returns the IGP routing protocol metric that applied when the
* route won the decision process. If the route has not won, this
* value is undefined.
*/
uint32_t igp_metric() const {return _metadata.igp_metric();}
/**
* @returns the original version of this route, before any filters
* were applied to it to modify it. If no filters have been
* applied, this may be this route itself.
*/
const SubnetRoute<A> *original_route() const {
if (_parent_route)
return _parent_route;
else
return this;
}
/**
* @returns the original version of this route, before any filters
* were applied to it to modify it. If no filters have been
* applied, NULL will be returned.
*/
const SubnetRoute<A>* parent_route() const { return _parent_route; }
/**
* @short record the original version of this route, before any
* filters were applied.
*
* @param parent the original version of this route.
*/
void set_parent_route(const SubnetRoute<A> *parent);
/**
* @short delete this route
*
* unref is called to delete a SubnetRoute, and should be called
* instead of calling delete on the route. SubnetRoutes are
* reference-counted, so unref decrements the reference count and
* deletes the storage only if the reference count reaches zero.
*/
void unref() const;
uint16_t refcount() const { return _metadata.refcount(); }
/**
* @return policy tags associated with route.
*/
const PolicyTags& policytags() const {
return _metadata.policytags();
}
/**
* Replaced policy tags of route.
*
* @param tags new policy tags for route.
*/
void set_policytags(const PolicyTags& tags) const {
_metadata.set_policytags(tags);
}
const RefPf& policyfilter(uint32_t i) const;
void set_policyfilter(uint32_t i, const RefPf& pf) const;
/**
* Set the "brief" mode flag on an candidate for aggregation.
*/
void set_aggr_brief_mode() const {
_metadata.set_aggr_brief_mode();
}
/**
* Clear the "brief" mode flag on an candidate for aggregation.
*/
void clear_aggr_brief_mode() const {
_metadata.clear_aggr_brief_mode();
}
/**
* Read the "brief" aggregation mode flag.
*/
bool aggr_brief_mode() const {
return _metadata.aggr_brief_mode();
}
/**
* Set the target prefix length on an candidate for aggregation.
* The field is also used for storing aggregation markers.
*
* @param preflen prefix length of the requested aggregate route.
*/
void set_aggr_prefix_len(uint32_t preflen) {
_metadata.set_aggr_prefix_len(preflen);
}
/**
* Read the aggregation prefix length marker.
* The field is also used for storing aggregation markers.
*/
uint32_t aggr_prefix_len() const {
return _metadata.aggr_prefix_len();
}
protected:
/**
* @short protected SubnetRoute destructor.
*
* The destructor is protected because you are not supposed to
* directly delete a SubnetRoute. Instead you should call unref()
* and the SubnetRoute will be deleted when it's reference count
* reaches zero.
*/
~SubnetRoute();
private:
void bump_refcount(int delta) const {
if (_metadata.bump_refcount(delta))
delete this;
}
//prevent accidental use of default assignment operator
const SubnetRoute<A>& operator=(const SubnetRoute<A>&);
/**
* _net is the subnet (address and prefix) for this route.
*/
IPNet<A> _net;
/**
* _attributes is a pointer to the path attribute list for this
* route. The actual data storage for the path attribute list is
* handled inside the attribute manager
*/
PAListRef<A> _attributes;
/**
* _parent_route is a pointer to the original version of this
* route, before any filters modified it. It may be NULL,
* indicating this is the original version.
*/
const SubnetRoute<A> *_parent_route;
mutable RouteMetaData _metadata;
};
/**
* @short a class to hold a reference to a SubnetRoute
*
* SubnetRouteRef holds a reference to a SubnetRoute. When it is
* deleted or goes out of scope, the SubnetRoute's reference count
* will be decreased, and the SubnetRoute may be deleted if the
* reference count reaches zero.
*/
template<class A>
class SubnetRouteRef
{
public:
SubnetRouteRef(SubnetRoute<A>* route) : _route(route)
{
if (_route)
_route->bump_refcount(1);
}
SubnetRouteRef(const SubnetRouteRef<A>& ref)
{
_route = ref._route;
if (_route)
_route->bump_refcount(1);
}
~SubnetRouteRef() {
if (_route)
_route->bump_refcount(-1);
}
SubnetRoute<A>* route() const {return _route;}
private:
//_route can be NULL
SubnetRoute<A>* _route;
};
/**
* @short a class to hold a const reference to a SubnetRoute
*
* SubnetRouteRef holds a const reference to a SubnetRoute. When it
* is deleted or goes out of scope, the SubnetRoute's reference count
* will be decreased, and the SubnetRoute may be deleted if the
* reference count reaches zero.
*/
template<class A>
class SubnetRouteConstRef
{
public:
SubnetRouteConstRef(const SubnetRoute<A>* route) : _route(route)
{
if (_route)
_route->bump_refcount(1);
}
SubnetRouteConstRef(const SubnetRouteConstRef<A>& ref)
{
_route = ref._route;
if (_route)
_route->bump_refcount(1);
}
~SubnetRouteConstRef() {
if (_route)
_route->bump_refcount(-1);
}
const SubnetRoute<A>* route() const {return _route;}
private:
//_route can be NULL
const SubnetRoute<A>* _route;
};
#endif // __BGP_SUBNET_ROUTE_HH__
Generated by: pavlin on kobe.xorp.net on Wed Jan 7 19:11:04 2009, using kdoc 2.0a54+XORP.