Route Storage Support in Gated

This component of the Gated core functionality provides a central repository for different protocol instances' currently preferred routes to destinations. It also provides an efficient way to store and process BGP route attribute information.

Gated Route Database

Gated provides a central repository for storing one or more of a protocol instance's preferred routes to a given destination. The route database module embodies a set of rules which select which protocol instance's route (and, if a protocol instance stores more than one route which one of these) to a same destination should be chosen.

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.

Route Database Data Structures

The main data structure in the route database is the 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_nodes, 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.

Route Database Entry Points

Protocol instances call 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.

Route Database Internals

The functions 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.


Gated AS Path Module

The Gated AS path module provides a facility to parse and otherwise manipulate BGP attributes. It is ostensibly separated from the BGP implementation under the expectation that other protocols (IS-IS) will also need similar facilities in the future.

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 Data Structures

The main data structure of the AS path module is an attribute descriptor block 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.

AS Path Module Entry Points

The primary function of the AS path module is performed by two routines 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.

AS Path Module Internals

The AS path hash table manipulation is relatively straightforward. 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.