Different protocol modules use the route database in different ways. OSPF maintains its link state database separately and instantiates routes into the routing database when it performs a link state computation. From OSPF, there can be only one route to a given destination. RIP and BGP add routes received in updates from peers; so the routing database may contain as many BGP routes to a destination as there are peers.
A sequence of atomic changes to the route database are made by explicitly locking the database. Whenever the database is unlocked, the route database module informs all protocol instances of all changes that have taken place; this can result in route update messages or unreachables being sent.
A detailed description of the data types, macros and function definitions of the route database may be found here.
rt_entry
.
This is a placeholder for route-specific information for a particular
destination/mask pair: next-hop, metric, preference, AS path and so on.
All routes to the same destination/mask pair are chained together
in a doubly-linked list. The head of this list is a
rt_head
structure. A rt_entry
contains a back pointer
to this structure. The rt_head
also contains
a pointer to the "active" (i.e. most preferred) route to this
destination/mask, a pointer to the previously "active" route and
other information.
The Gated route database maintains a single radix tree for all
the routes in the database (actually, one per address family).
Tree searches are keyed on destination/mask pairs. The internal
nodes of this tree are
radix_node
s,
and each internal node points to a rt_head
structure.
A figure helps explain the routing database data structures better.
Some other data structures are of interest to protocol implementations.
The rt_list
structure contains a list of changes that
have occurred to the database; this list is communicated to all
protocol instances everytime a change occurs.
The rt_parms
is used to temporarily store route parameters
when parsing routing protocol messages; a rt_entry
is
later created for the route.
When Gated selects the ``active'' route, it notifies all protocol
instances (this corresponds to an OSPF instance, or a BGP connection)
of the new ``active'' route. A protocol instance's export
policy may allow it to announce that route. The rt_bits
field encodes the protocol instances that are currently announcing
a particular route. This field is a bit mask; each protocol instance
is allocated a ``route bit'' from a global bitmask -- if a particular
bit in the rt_bits
bitmask is set, it means that the
protocol instance allocated that bit is announcing the route.
Protocol instances maintain their own maps of routes they have stored
in the routing database. Given a rt_entry
, how do protocol
instances find out which of their own data structures contain references
to the rt_entry
? Such protocol specific data is stored in
a byte array in the route entry's rt_head
. The position
of this data within the byte array is determined by the protocol's
``route bit''. To each protocol instance, Gated statically allocates
block of locations in this byte array where it may store protocol specific
data. Gated maintains a global bitmask of allocated locations
in the byte array (in the rttsi_map
) as well as a mapping
from a protocol's route bit to the allocated locations
(rtbit_info
). These data structures are better explained
using the following figure.
rt_add()
to add a route with the specified parameters and to the specified
destination/mask pair to the route database. This function
allocates a rt_head
and inserts that into the radix
tree (if necessary, when no other routes to the same destination exist).
The function
rt_delete()
logically deletes a route from the route database. Resources allocated
to the route are not released immediately, pending notification
of the delete to all protocol instances that may be announcing the route.
The functions
rttsi_alloc()
,
rttsi_set()
, and
rttsi_get()
,
respectively allocate a contiguous block of bytes for storing
protocol-specific data in a rt_head
entry, store and
retrieve protocol instance specific data from a specified
rt_head
.
When a protocol instance receives an update for a route previously sent
from a peer, it calls
rt_change_aspath()
to update the route entry with the new information. As an optimization,
if the route in question is currently ``active'', Gated stores the
changes separately and applies them when the route is re-advertised.
The function
rthlist_all()
walks through a specified address family's radix tree and returns
a list of all rt_head
entries in the tree. Variant functions
exist for returning the list of all rt_entry
elements
in the tree, or the list of those specifying a certain criterion.
Finally,
rt_new_policy()
is called when a re-configuration occurs, and
rt_flash_update()
is queued by rt_close
and called from the task scheduler
to notify the kernel routing table and all protocol instances of the
most recent routing table changes.
rt_table_add()
,
rt_table_locate()
,
rt_table_delete()
,
respectively add, find, and delete a rt_head
entry from
a radix tree, given a destination address and mask. These are standard
radix tree operations.
The functions prefixed by
rt_event_
flag a rt_entry
with a specified state change. Actions
related to a state change (e.g. when a route is deleted, a new active
route must be computed) are also performed here.
The function
rt_insert()
encodes the routing database's rules on selecting the ``active'' route.
The route with the highest preference is selected for the ``active''
route. To break ties, routes with shorter AS paths are preferred. To
break ties among these, routes with the lowest next-hop addresses are
chosen.
In the abstract, given a set of attributes (origin, AS path and optional transitive attributes), this facility returns a descriptor for those attributes. This module also maintains the invariant that identical attribute sets share the same descriptor.
A detailed description of the data types, macros and function definitions of the AS path module may be found here.
as_path
. This is a variable sized
block containing the origin attribute, the AS path, and any optional
transitive attributes found in a route's attribute list.
If two routes have the same attributes, they share the same
as_path
struct. The descriptor contains a reference
count of the number of routes sharing an AS path.
An AS path referenced by one or more routes is stored in a global
hash table path_list
, for quick retrieval. The hash
value is a function of the AS path length, the origin attribute,
and the length of the optional transitive attributes.
One other data structure of interest internally is the
as_path_list
structure. This is used to aggregate
a number of different routes; a list of these structures denotes
the AS paths of the routes contributing to the aggregate.
aspath_attr()
and
aspath_format_v4()
.
Given a pointer to a BGP update message containing an attribute list,
aspath_attr()
returns a pointer to a as_path
struct having the same attributes.
aspath_format_v4()
performs the opposite function: given
an as_path
struct, it formulates a BGP update message
attributes part using the contents of the as_path
descriptor.
Whenever routing updates are received and the
Gated routing database changes,
Gated updates its forwarding table. Before it does so, it tries to
aggregate the route changes, if possible.
aspath_do_aggregation()
is used to compute the AS path of the aggregate route.
Finally,
aspath_rt_build()
is used to associate an AS path descriptor with a rt_entry
.
This simply ups the reference count in the common case.
aspath_find()
implements the invariant of having matching attribute sets be represented
by a single descriptor.
AS path memory allocation uses the fixed block allocator for the
two common cases of attribute blocks being either smaller than 32 bytes
or 64 bytes, and uses malloc()
otherwise.
The Gated implementation allows a router running Gated to belong to a
number of different ASs. An AS path may have been advertised to BGP
instances running in different ASs on the same router. When this
router advertises the route, it must correctly include all the local
ASs which received this advertisement and passed it on.
The AS path module maintains an array of "local" AS numbers.
The aslocal_*()
set of functions is used to manipulate
this array. The as_path
descriptor maintains a bitmask of
local ASs (a bit position in the bitmask indicates the index into
the local AS array) which received this AS path. When the AS path module
formulates an update message, it ensures that it lists all the local
ASs relevant to the AS path as an AS set.