BIRD Programmer's Documentation: Core

Next Previous Contents

## 2. Core

## 2.1 Forwarding Information Base

FIB is a data structure designed for storage of routes indexed by their network prefixes. It supports insertion, deletion, searching by prefix, `routing' (in CIDR sense, that is searching for a longest prefix matching a given IP address) and (which makes the structure very tricky to implement) asynchronous reading, that is enumerating the contents of a FIB while other modules add, modify or remove entries.

Internally, each FIB is represented as a collection of nodes of type fib_node indexed using a sophisticated hashing mechanism. We use two-stage hashing where we calculate a 16-bit primary hash key independent on hash table size and then we just divide the primary keys modulo table size to get a real hash key used for determining the bucket containing the node. The lists of nodes in each bucket are sorted according to the primary hash key, hence if we keep the total number of buckets to be a power of two, re-hashing of the structure keeps the relative order of the nodes.

To get the asynchronous reading consistent over node deletions, we need to keep a list of readers for each node. When a node gets deleted, its readers are automatically moved to the next node in the table.

Basic FIB operations are performed by functions defined by this module, enumerating of FIB contents is accomplished by using the FIB_WALK() macro or FIB_ITERATE_START() if you want to do it asynchronously.

For simple iteration just place the body of the loop between FIB_WALK() and FIB_WALK_END(). You can't modify the FIB during the iteration (you can modify data in the node, but not add or remove nodes).

If you need more freedom, you can use the FIB_ITERATE_*() group of macros. First, you initialize an iterator with FIB_ITERATE_INIT(). Then you can put the loop body in between FIB_ITERATE_START() and FIB_ITERATE_END(). In addition, the iteration can be suspended by calling FIB_ITERATE_PUT(). This'll link the iterator inside the FIB. While suspended, you may modify the FIB, exit the current function, etc. To resume the iteration, enter the loop again. You can use FIB_ITERATE_UNLINK() to unlink the iterator (while iteration is suspended) in cases like premature end of FIB iteration.

Note that the iterator must not be destroyed when the iteration is suspended, the FIB would then contain a pointer to invalid memory. Therefore, after each FIB_ITERATE_INIT() or FIB_ITERATE_PUT() there must be either FIB_ITERATE_START() or FIB_ITERATE_UNLINK() before the iterator is destroyed.

### Function

void fib_init (struct fib * f, pool * p, uint addr_type, uint node_size, uint node_offset, uint hash_order, fib_init_fn init) -- initialize a new FIB

### Arguments

struct fib * f

  the FIB to be initialized (the structure itself being allocated by the caller)

pool * p

  pool to allocate the nodes in

uint addr_type

  -- undescribed --

uint node_size

  node size to be used (each node consists of a standard header fib_node followed by user data)

uint node_offset

  -- undescribed --

uint hash_order

  initial hash order (a binary logarithm of hash table size), 0 to use default order (recommended)

fib_init_fn init

  pointer a function to be called to initialize a newly created node

### Description

This function initializes a newly allocated FIB and prepares it for use.

### Function

void * fib_find (struct fib * f, const net_addr * a) -- search for FIB node by prefix

### Arguments

struct fib * f

  FIB to search in

const net_addr * a

  -- undescribed --

### Description

Search for a FIB node corresponding to the given prefix, return a pointer to it or NULL if no such node exists.

### Function

void * fib_get (struct fib * f, const net_addr * a) -- find or create a FIB node

### Arguments

struct fib * f

  FIB to work with

const net_addr * a

  -- undescribed --

### Description

Search for a FIB node corresponding to the given prefix and return a pointer to it. If no such node exists, create it.

### Function

void * fib_route (struct fib * f, const net_addr * n) -- CIDR routing lookup

### Arguments

struct fib * f

  FIB to search in

const net_addr * n

  network address

### Description

Search for a FIB node with longest prefix matching the given network, that is a node which a CIDR router would use for routing that network.

### Function

void fib_delete (struct fib * f, void * E) -- delete a FIB node

### Arguments

struct fib * f

  FIB to delete from

void * E

  entry to delete

### Description

This function removes the given entry from the FIB, taking care of all the asynchronous readers by shifting them to the next node in the canonical reading order.

### Function

void fib_free (struct fib * f) -- delete a FIB

### Arguments

struct fib * f

  FIB to be deleted

### Description

This function deletes a FIB -- it frees all memory associated with it and all its entries.

### Function

void fib_check (struct fib * f) -- audit a FIB

### Arguments

struct fib * f

  FIB to be checked

### Description

This debugging function audits a FIB by checking its internal consistency. Use when you suspect somebody of corrupting innocent data structures.

## 2.2 Routing tables

Routing tables are probably the most important structures BIRD uses. They hold all the information about known networks, the associated routes and their attributes.

There are multiple routing tables (a primary one together with any number of secondary ones if requested by the configuration). Each table is basically a FIB containing entries describing the individual destination networks. For each network (represented by structure net), there is a one-way linked list of route entries (rte), the first entry on the list being the best one (i.e., the one we currently use for routing), the order of the other ones is undetermined.

The rte contains information about the route. There are net and src, which together forms a key identifying the route in a routing table. There is a pointer to a rta structure (see the route attribute module for a precise explanation) holding the route attributes, which are primary data about the route. There are several technical fields used by routing table code (route id, REF_* flags), There is also the pflags field, holding protocol-specific flags. They are not used by routing table code, but by protocol-specific hooks. In contrast to route attributes, they are not primary data and their validity is also limited to the routing table.

There are several mechanisms that allow automatic update of routes in one routing table (dst) as a result of changes in another routing table (src). They handle issues of recursive next hop resolving, flowspec validation and RPKI validation.

The first such mechanism is handling of recursive next hops. A route in the dst table has an indirect next hop address, which is resolved through a route in the src table (which may also be the same table) to get an immediate next hop. This is implemented using structure hostcache attached to the src table, which contains hostentry structures for each tracked next hop address. These structures are linked from recursive routes in dst tables, possibly multiple routes sharing one hostentry (as many routes may have the same indirect next hop). There is also a trie in the hostcache, which matches all prefixes that may influence resolving of tracked next hops.

When a best route changes in the src table, the hostcache is notified using an auxiliary export request, which checks using the trie whether the change is relevant and if it is, then it schedules asynchronous hostcache recomputation. The recomputation is done by rt_update_hostcache() (called as an event of src table), it walks through all hostentries and resolves them (by rt_update_hostentry()). It also updates the trie. If a change in hostentry resolution was found, then it schedules asynchronous nexthop recomputation of associated dst table. That is done by rt_next_hop_update() (called from rt_event() of dst table), it iterates over all routes in the dst table and re-examines their hostentries for changes. Note that in contrast to hostcache update, next hop update can be interrupted by main loop. These two full-table walks (over hostcache and dst table) are necessary due to absence of direct lookups (route -> affected nexthop, nexthop -> its route).

The second mechanism is for flowspec validation, where validity of flowspec routes depends of resolving their network prefixes in IP routing tables. This is similar to the recursive next hop mechanism, but simpler as there are no intermediate hostcache and hostentries (because flows are less likely to share common net prefix than routes sharing a common next hop). Every dst table has its own export request in every src table. Each dst table has its own trie of prefixes that may influence validation of flowspec routes in it (flowspec_trie).

When a best route changes in the src table, the notification mechanism is invoked by the export request which checks its dst table's trie to see whether the change is relevant, and if so, an asynchronous re-validation of flowspec routes in the dst table is scheduled. That is also done by function rt_next_hop_update(), like nexthop recomputation above. It iterates over all flowspec routes and re-validates them. It also recalculates the trie.

Note that in contrast to the hostcache update, here the trie is recalculated during the rt_next_hop_update(), which may be interleaved with IP route updates. The trie is flushed at the beginning of recalculation, which means that such updates may use partial trie to see if they are relevant. But it works anyway! Either affected flowspec was already re-validated and added to the trie, then IP route change would match the trie and trigger a next round of re-validation, or it was not yet re-validated and added to the trie, but will be re-validated later in this round anyway.

The third mechanism is used for RPKI re-validation of IP routes and it is the simplest. It is also an auxiliary export request belonging to the appropriate channel, triggering its reload/refeed timer after a settle time.

### Function

int net_roa_check (rtable * tp, const net_addr * n, u32 asn) -- check validity of route origination in a ROA table

### Arguments

rtable * tp

  -- undescribed --

const net_addr * n

  network prefix to check

u32 asn

  AS number of network prefix

### Description

Implements RFC 6483 route validation for the given network prefix. The procedure is to find all candidate ROAs - ROAs whose prefixes cover the given network prefix. If there is no candidate ROA, return ROA_UNKNOWN. If there is a candidate ROA with matching ASN and maxlen field greater than or equal to the given prefix length, return ROA_VALID. Otherwise, return ROA_INVALID. If caller cannot determine origin AS, 0 could be used (in that case ROA_VALID cannot happen). Table tab must have type NET_ROA4 or NET_ROA6, network n must have type NET_IP4 or NET_IP6, respectively.

### Function

enum aspa_result aspa_check (rtable * tab, const adata * path, bool force_upstream) -- check validity of AS Path in an ASPA table

### Arguments

rtable * tab

  ASPA table

const adata * path

  AS Path to check

bool force_upstream

  -- undescribed --

### Description

Implements draft-ietf-sidrops-aspa-verification-16.

Straightforward implementation of the draft algorithm would be messy, and would involve repeatedly checking the table for the same ASN. Therefore, we check the path in a streamed way.

First, necessary preparations are done, to unstuff the path (COMPRESSED_AS_PATH, as of -24), and also refusing confeds and sets right away.

For the algorithm, it's worth noting that the draft indexes the path from its end and from one, which has repeatedly brought off-by-one errors in our implementation, together with measuring the lengths of the up/down ramps. We index the path from its beginning and from zero.

We walk the AS Path from its beginning (which is the local-most ASN) to its end (which is the alleged origin ASN), and keep four pointers (indices) to it:

- max_up, the leftmost ASN which can still be part of the up-ramp for UNKNOWN - min_up, the leftmost ASN which is a definite part of the up-ramp for VALID - max_down, the rightmost ASN which can still be part of the down-ramp for UNKNOWN - min_down, the rightmost ASN which is a definite part of the down-ramp for VALID

The draft calls these points the ramp apexes (or apices?).

All these pointers are initially zero. Technically, they should be undefined, but for length-one path, both the up-ramp and down-ramp apex is actually at index zero.

The down-ramp then goes from zero index to `min_down` for VALID, and to `max_down` for UNKNOWN. The up-ramp goes backwards from the other end (`nsz-1`) to `min_up` for VALID, and to `max_up` for UNKNOWN.

### Example

min_down = 2 max_down = 4 min_up = 4 max_up = 3

+---+---+---+---+---+---+---+ `0` 1 `2` 3 `4` 5 `6` `down-ramp` ????? `-------` `-----------` ? `up-ramp` +---------------------------+

Here, again, AS(2) has no ASPA published, ending the certain down-ramp, and AS(4) has no ASPA published, ending the certain up-ramp. But, behold! The uncertain down-ramp must be ended here by AS(4) actually publishing ASPA not including AS(5).

Therefore, this scenario is impossible.

We process the AS Path by gradually appending more AS's to an empty path.

In all steps, it is invariant that, for the downstream algorithm, the certain (min) down-ramp and up-ramp must cover the whole path to get `ASPA_VALID`, and otherwise the possible (max) down-ramp and up-ramp must cover the whole path to get `ASPA_UNKNOWN`. Failure to cover the path yields `ASPA_INVALID`. The draft, as of -24, specifies the same but in double-negative.

Path coverage means that if `min_up == min_down + 1`, the path is still `ASPA_VALID` because the apexes are touching, as shown in sec. 5.1 of the draft -24.

We evaluate this condition at the end of the function. The upstream algorithm differs from the downstream algorithm only in such a way that the down-ramp is missing.

In every step, we look at the current ASN (indicated by ap) and its left and right neighbor, and ask:

- is there an ASPA by this ASN including the left neighbor? If yes, adding this ASN does not change `max_up` and `min_up` because the up-ramp is extended by this - is there an ASPA by this ASN including the right neighbor? If yes, adding the ASN of the right neighbor may move `max_down` and `min_down` to that one, unless the down-ramp is already cut off - is there any ASPA at all but not for the left neighbor? If yes, the up-ramp is broken by this relationship, and we have to move both `min_up` and `max_up` to this ASN - is there any ASPA at all but not for the right neighbor? If yes, the down-ramp ends here, unless it has been cut off by a previous occurence of this situation. We don't move anything. - is there no ASPA? If yes, we move `min_up` because the certain up-ramp is not extended by this. Contrary, `max_up` stays. The same way but opposite, we may move `max_down` (if still pointing here) because the maybe down-ramp may be extended by this.

The implementation may look slightly inefficient but we actually want to extend it later so that it always returns the complete information, i.e. all relevant AS Path chunks, for the users to investigate in the filters.

After ASPA gets enough traction so that this function performance is actually measurable, we expect to update the ASPA checking mechanisms to cache all the results, and combine the final result from various path chunks, without having to do an ASPA table lookup for every single unique ASN in the path.

### Example

min_down = 2 max_down = 4 min_up = 4 max_up = 3

+---+---+---+---+---+---+---+ `0` 1 `2` 3 `4` 5 `6` `down-ramp` ????? `-------` `-----------` ? `up-ramp` +---------------------------+

Here, again, AS(2) has no ASPA published, ending the certain down-ramp, and AS(4) has no ASPA published, ending the certain up-ramp. But, behold! The uncertain down-ramp must be ended here by AS(4) actually publishing ASPA not including AS(5).

Therefore, this scenario is impossible.

We process the AS Path by gradually appending more AS's to an empty path.

In all steps, it is invariant that, for the downstream algorithm, the certain (min) down-ramp and up-ramp must cover the whole path to get `ASPA_VALID`, and otherwise the possible (max) down-ramp and up-ramp must cover the whole path to get `ASPA_UNKNOWN`. Failure to cover the path yields `ASPA_INVALID`. The draft, as of -24, specifies the same but in double-negative.

Path coverage means that if `min_up == min_down + 1`, the path is still `ASPA_VALID` because the apexes are touching, as shown in sec. 5.1 of the draft -24.

We evaluate this condition at the end of the function. The upstream algorithm differs from the downstream algorithm only in such a way that the down-ramp is missing.

In every step, we look at the current ASN (indicated by ap) and its left and right neighbor, and ask:

- is there an ASPA by this ASN including the left neighbor? If yes, adding this ASN does not change `max_up` and `min_up` because the up-ramp is extended by this - is there an ASPA by this ASN including the right neighbor? If yes, adding the ASN of the right neighbor may move `max_down` and `min_down` to that one, unless the down-ramp is already cut off - is there any ASPA at all but not for the left neighbor? If yes, the up-ramp is broken by this relationship, and we have to move both `min_up` and `max_up` to this ASN - is there any ASPA at all but not for the right neighbor? If yes, the down-ramp ends here, unless it has been cut off by a previous occurence of this situation. We don't move anything. - is there no ASPA? If yes, we move `min_up` because the certain up-ramp is not extended by this. Contrary, `max_up` stays. The same way but opposite, we may move `max_down` (if still pointing here) because the maybe down-ramp may be extended by this.

The implementation may look slightly inefficient but we actually want to extend it later so that it always returns the complete information, i.e. all relevant AS Path chunks, for the users to investigate in the filters.

After ASPA gets enough traction so that this function performance is actually measurable, we expect to update the ASPA checking mechanisms to cache all the results, and combine the final result from various path chunks, without having to do an ASPA table lookup for every single unique ASN in the path.

### Example

min_down = 2 max_down = 4 min_up = 4 max_up = 3

+---+---+---+---+---+---+---+ `0` 1 `2` 3 `4` 5 `6` `down-ramp` ????? `-------` `-----------` ? `up-ramp` +---------------------------+

Here, again, AS(2) has no ASPA published, ending the certain down-ramp, and AS(4) has no ASPA published, ending the certain up-ramp. But, behold! The uncertain down-ramp must be ended here by AS(4) actually publishing ASPA not including AS(5).

Therefore, this scenario is impossible.

We process the AS Path by gradually appending more AS's to an empty path.

In all steps, it is invariant that, for the downstream algorithm, the certain (min) down-ramp and up-ramp must cover the whole path to get `ASPA_VALID`, and otherwise the possible (max) down-ramp and up-ramp must cover the whole path to get `ASPA_UNKNOWN`. Failure to cover the path yields `ASPA_INVALID`. The draft, as of -24, specifies the same but in double-negative.

Path coverage means that if `min_up == min_down + 1`, the path is still `ASPA_VALID` because the apexes are touching, as shown in sec. 5.1 of the draft -24.

We evaluate this condition at the end of the function. The upstream algorithm differs from the downstream algorithm only in such a way that the down-ramp is missing.

In every step, we look at the current ASN (indicated by ap) and its left and right neighbor, and ask:

- is there an ASPA by this ASN including the left neighbor? If yes, adding this ASN does not change `max_up` and `min_up` because the up-ramp is extended by this - is there an ASPA by this ASN including the right neighbor? If yes, adding the ASN of the right neighbor may move `max_down` and `min_down` to that one, unless the down-ramp is already cut off - is there any ASPA at all but not for the left neighbor? If yes, the up-ramp is broken by this relationship, and we have to move both `min_up` and `max_up` to this ASN - is there any ASPA at all but not for the right neighbor? If yes, the down-ramp ends here, unless it has been cut off by a previous occurence of this situation. We don't move anything. - is there no ASPA? If yes, we move `min_up` because the certain up-ramp is not extended by this. Contrary, `max_up` stays. The same way but opposite, we may move `max_down` (if still pointing here) because the maybe down-ramp may be extended by this.

The implementation may look slightly inefficient but we actually want to extend it later so that it always returns the complete information, i.e. all relevant AS Path chunks, for the users to investigate in the filters.

After ASPA gets enough traction so that this function performance is actually measurable, we expect to update the ASPA checking mechanisms to cache all the results, and combine the final result from various path chunks, without having to do an ASPA table lookup for every single unique ASN in the path.

### Example

min_down = 2 max_down = 4 min_up = 4 max_up = 3

+---+---+---+---+---+---+---+ `0` 1 `2` 3 `4` 5 `6` `down-ramp` ????? `-------` `-----------` ? `up-ramp` +---------------------------+

Here, again, AS(2) has no ASPA published, ending the certain down-ramp, and AS(4) has no ASPA published, ending the certain up-ramp. But, behold! The uncertain down-ramp must be ended here by AS(4) actually publishing ASPA not including AS(5).

Therefore, this scenario is impossible.

We process the AS Path by gradually appending more AS's to an empty path.

In all steps, it is invariant that, for the downstream algorithm, the certain (min) down-ramp and up-ramp must cover the whole path to get `ASPA_VALID`, and otherwise the possible (max) down-ramp and up-ramp must cover the whole path to get `ASPA_UNKNOWN`. Failure to cover the path yields `ASPA_INVALID`. The draft, as of -24, specifies the same but in double-negative.

Path coverage means that if `min_up == min_down + 1`, the path is still `ASPA_VALID` because the apexes are touching, as shown in sec. 5.1 of the draft -24.

We evaluate this condition at the end of the function. The upstream algorithm differs from the downstream algorithm only in such a way that the down-ramp is missing.

In every step, we look at the current ASN (indicated by ap) and its left and right neighbor, and ask:

- is there an ASPA by this ASN including the left neighbor? If yes, adding this ASN does not change `max_up` and `min_up` because the up-ramp is extended by this - is there an ASPA by this ASN including the right neighbor? If yes, adding the ASN of the right neighbor may move `max_down` and `min_down` to that one, unless the down-ramp is already cut off - is there any ASPA at all but not for the left neighbor? If yes, the up-ramp is broken by this relationship, and we have to move both `min_up` and `max_up` to this ASN - is there any ASPA at all but not for the right neighbor? If yes, the down-ramp ends here, unless it has been cut off by a previous occurence of this situation. We don't move anything. - is there no ASPA? If yes, we move `min_up` because the certain up-ramp is not extended by this. Contrary, `max_up` stays. The same way but opposite, we may move `max_down` (if still pointing here) because the maybe down-ramp may be extended by this.

The implementation may look slightly inefficient but we actually want to extend it later so that it always returns the complete information, i.e. all relevant AS Path chunks, for the users to investigate in the filters.

After ASPA gets enough traction so that this function performance is actually measurable, we expect to update the ASPA checking mechanisms to cache all the results, and combine the final result from various path chunks, without having to do an ASPA table lookup for every single unique ASN in the path.

### Returns

`ASPA_VALID`, `ASPA_UNKNOWN` or `ASPA_INVALID`.

### Accesses

tab for reading.

### Function

void rte_free (struct rte_storage * e, struct rtable_private * tab) -- delete a rte (happens later)

### Arguments

struct rte_storage * e

  struct rte_storage to be deleted

struct rtable_private * tab

  the table which the rte belongs to

### Description

rte_free() deletes the given rte from the routing table it's linked to.

### Function

bool export_filter (struct channel * c, rte * rt, int silent) -- evaluate export filters

### Arguments

struct channel * c

  related channel

rte * rt

  route to evaluate; mutable, may be modified by the filters (!)

int silent

  no logging, reuse old results

### Description

Evaluate the filters on the export, including the preexport hook of the exporting protocol. Returns the result of the filter, i.e. true if accept, false if reject.

### Function

void do_rt_notify (struct channel * c, const net_addr * net, rte * new, const rte * old) -- actually export the route to the protocol

### Arguments

struct channel * c

  channel to use

const net_addr * net

  related network

rte * new

  announced route

const rte * old

  withdrawn route

### Description

This function does all the common things which must happen before the protocol's rt_notify() hook is called, most notably channel limit checks, stats update and logging.

### Function

void rt_notify_basic (struct channel * c, const rte * new, const rte * old, const rte * trte) -- common route exporter for RA_OPTIMAL and RA_ANY

### Arguments

struct channel * c

  channel to use

const rte * new

  announced route

const rte * old

  withdrawn route

const rte * trte

  -- undescribed --

### Description

This function expects to get refined pairs of announced and withdrawn route which have already been selected so that the old route has been seen before.

### Function

void channel_notify_optimal (void * _channel) -- process the export queue for RA_OPTIMAL

### Arguments

void * _channel

  channel to use

### Description

Actually an event hook. Walks the export journal and distills pairs of announced and withdrawn routes for rt_notify_basic(). Scheduled when the journal gets some new items.

### Function

void rt_refresh_begin (struct rt_import_request * req) -- start a refresh cycle

### Arguments

struct rt_import_request * req

  -- undescribed --

### Description

This function starts a refresh cycle for given routing table and announce hook. The refresh cycle is a sequence where the protocol sends all its valid routes to the routing table (by rte_update()). After that, all protocol routes (more precisely routes with c as sender) not sent during the refresh cycle but still in the table from the past are pruned. This is implemented by marking all related routes as stale by REF_STALE flag in rt_refresh_begin(), then marking all related stale routes with REF_DISCARD flag in rt_refresh_end() and then removing such routes in the prune loop.

### Function

void rt_refresh_end (struct rt_import_request * req) -- end a refresh cycle

### Arguments

struct rt_import_request * req

  -- undescribed --

### Description

This function ends a refresh cycle for given routing table and announce hook. See rt_refresh_begin() for description of refresh cycles.

### Function

void rt_refresh_trace (struct rtable_private * tab, struct rt_import_hook * ih, const char * msg) -- log information about route refresh

### Arguments

struct rtable_private * tab

  table

struct rt_import_hook * ih

  import hook doing the route refresh

const char * msg

  what is happening

### Description

This function consistently logs route refresh messages.

### Function

void rte_dump (struct dump_request * dreq, struct rte_storage * e) -- dump a route

### Arguments

struct dump_request * dreq

  -- undescribed --

struct rte_storage * e

  rte to be dumped

### Description

This functions dumps contents of a rte to debug output.

### Function

void rt_dump (struct dump_request * dreq, rtable * tab) -- dump a routing table

### Arguments

struct dump_request * dreq

  -- undescribed --

rtable * tab

  -- undescribed --

### Description

This function dumps contents of a given routing table to debug output.

### Function

void rt_dump_all (struct dump_request * dreq) -- dump all routing tables

### Arguments

struct dump_request * dreq

  -- undescribed --

### Description

This function dumps contents of all routing tables to debug output.

### Function

void rt_init (void) -- initialize routing tables

### Description

This function is called during BIRD startup. It initializes the routing table module.

### Function

void rt_prune_table (void * _tab) -- prune a routing table

### Arguments

void * _tab

  -- undescribed --

### Description

The prune loop scans routing tables and removes routes belonging to flushing protocols, discarded routes and also stale network entries. It is called from rt_event(). The event is rescheduled if the current iteration do not finish the table. The pruning is directed by the prune state (prune_state), specifying whether the prune cycle is scheduled or running, and there is also a persistent pruning iterator (prune_fit).

The prune loop is used also for channel flushing. For this purpose, the channels to flush are marked before the iteration and notified after the iteration.

### Function

void rt_unlock_trie (struct rtable_private * tab, const struct f_trie * trie) -- unlock a prefix trie of a routing table

### Arguments

struct rtable_private * tab

  routing table with prefix trie to be locked

const struct f_trie * trie

  value returned by matching rt_lock_trie()

### Description

Done for trie locked by rt_lock_trie() after walk over the trie is done. It may free the trie and schedule next trie pruning.

### Function

void rt_lock_table_priv (struct rtable_private * r, const char * file, uint line) -- lock a routing table

### Arguments

struct rtable_private * r

  routing table to be locked

const char * file

  -- undescribed --

uint line

  -- undescribed --

### Description

Lock a routing table, because it's in use by a protocol, preventing it from being freed when it gets undefined in a new configuration.

### Function

void rt_unlock_table_priv (struct rtable_private * r, const char * file, uint line) -- unlock a routing table

### Arguments

struct rtable_private * r

  routing table to be unlocked

const char * file

  -- undescribed --

uint line

  -- undescribed --

### Description

Unlock a routing table formerly locked by rt_lock_table(), that is decrease its use count and delete it if it's scheduled for deletion by configuration changes.

### Function

void rt_commit (struct config * new, struct config * old) -- commit new routing table configuration

### Arguments

struct config * new

  new configuration

struct config * old

  original configuration or NULL if it's boot time config

### Description

Scan differences between old and new configuration and modify the routing tables according to these changes. If new defines a previously unknown table, create it, if it omits a table existing in old, schedule it for deletion (it gets deleted when all protocols disconnect from it by calling rt_unlock_table()), if it exists in both configurations, leave it unchanged.

## 2.3 Route attribute cache

Each route entry carries a set of route attributes. Several of them vary from route to route, but most attributes are usually common for a large number of routes. To conserve memory, we've decided to store only the varying ones directly in the rte and hold the rest in a special structure called rta which is shared among all the rte's with these attributes.

Each rta contains all the static attributes of the route (i.e., those which are always present) as structure members and a list of dynamic attributes represented by a linked list of ea_list structures, each of them consisting of an array of eattr's containing the individual attributes. An attribute can be specified more than once in the ea_list chain and in such case the first occurrence overrides the others. This semantics is used especially when someone (for example a filter) wishes to alter values of several dynamic attributes, but it wants to preserve the original attribute lists maintained by another module.

Each eattr contains an attribute identifier (split to protocol ID and per-protocol attribute ID), protocol dependent flags, a type code (consisting of several bit fields describing attribute characteristics) and either an embedded 32-bit value or a pointer to a adata structure holding attribute contents.

There exist two variants of rta's -- cached and un-cached ones. Un-cached rta's can have arbitrarily complex structure of ea_list's and they can be modified by any module in the route processing chain. Cached rta's have their attribute lists normalized (that means at most one ea_list is present and its values are sorted in order to speed up searching), they are stored in a hash table to make fast lookup possible and they are provided with a use count to allow sharing.

Routing tables always contain only cached rta's.

### Function

struct rte_src * rt_find_source_global (u32 id)

### Arguments

u32 id

  requested global ID

### Route attribute cache

sources stored by their ID. Checking for non-existent or foreign source is unsafe.

### Description

Returns the found source or dies. Result of this function is guaranteed to be a valid source as long as the caller owns it.

### Function

struct nexthop_adata * nexthop_merge (struct nexthop_adata * xin, struct nexthop_adata * yin, int max, linpool * lp) -- merge nexthop lists

### Arguments

struct nexthop_adata * xin

  -- undescribed --

struct nexthop_adata * yin

  -- undescribed --

int max

  max number of nexthops

linpool * lp

  linpool for allocating nexthops

### Description

The nexthop_merge() function takes two nexthop lists x and y and merges them, eliminating possible duplicates. The input lists must be sorted and the result is sorted too. The number of nexthops in result is limited by max. New nodes are allocated from linpool lp.

The arguments rx and ry specify whether corresponding input lists may be consumed by the function (i.e. their nodes reused in the resulting list), in that case the caller should not access these lists after that. To eliminate issues with deallocation of these lists, the caller should use some form of bulk deallocation (e.g. stack or linpool) to free these nodes when the resulting list is no longer needed. When reusability is not set, the corresponding lists are not modified nor linked from the resulting list.

### Function

eattr * ea_find_by_id (ea_list * e, unsigned id) -- find an extended attribute

### Arguments

ea_list * e

  attribute list to search in

unsigned id

  attribute ID to search for

### Description

Given an extended attribute list, ea_find() searches for a first occurrence of an attribute with specified ID, returning either a pointer to its eattr structure or NULL if no such attribute exists.

### Function

eattr * ea_walk (struct ea_walk_state * s, uint id, uint max) -- walk through extended attributes

### Arguments

struct ea_walk_state * s

  walk state structure

uint id

  start of attribute ID interval

uint max

  length of attribute ID interval

### Description

Given an extended attribute list, ea_walk() walks through the list looking for first occurrences of attributes with ID in specified interval from id to (id + max - 1), returning pointers to found eattr structures, storing its walk state in s for subsequent calls.

The function ea_walk() is supposed to be called in a loop, with initially zeroed walk state structure s with filled the initial extended attribute list, returning one found attribute in each call or NULL when no other attribute exists. The extended attribute list or the arguments should not be modified between calls. The maximum value of max is 128.

### Function

void ea_do_prune (ea_list * e)

### Arguments

ea_list * e

  -- undescribed --

### Description

for this reason.

### Function

void ea_sort (ea_list * e) -- sort an attribute list

### Arguments

ea_list * e

  list to be sorted

### Description

This function takes a ea_list chain and sorts the attributes within each of its entries.

If an attribute occurs multiple times in a single ea_list, ea_sort() leaves only the first (the only significant) occurrence.

### Function

unsigned ea_scan (const ea_list * e, u32 upto) -- estimate attribute list size

### Arguments

const ea_list * e

  attribute list

u32 upto

  -- undescribed --

### Description

This function calculates an upper bound of the size of a given ea_list after merging with ea_merge().

### Function

void ea_merge (ea_list * e, ea_list * t, u32 upto) -- merge segments of an attribute list

### Arguments

ea_list * e

  attribute list

ea_list * t

  buffer to store the result to

u32 upto

  -- undescribed --

### Description

This function takes a possibly multi-segment attribute list and merges all of its segments to one.

The primary use of this function is for ea_list normalization: first call ea_scan() to determine how much memory will the result take, then allocate a buffer (usually using alloca()), merge the segments with ea_merge() and finally sort and prune the result by calling ea_sort().

### Function

int ea_same (ea_list * x, ea_list * y) -- compare two ea_list's

### Arguments

ea_list * x

  attribute list

ea_list * y

  attribute list

### Description

ea_same() compares two normalized attribute lists x and y and returns 1 if they contain the same attributes, 0 otherwise.

### Function

void ea_show (struct cli * c, const eattr * e) -- print an eattr to CLI

### Arguments

struct cli * c

  destination CLI

const eattr * e

  attribute to be printed

### Description

This function takes an extended attribute represented by its eattr structure and prints it to the CLI according to the type information.

If the protocol defining the attribute provides its own get_attr() hook, it's consulted first.

### Function

void ea_dump (struct dump_request * dreq, ea_list * e) -- dump an extended attribute

### Arguments

struct dump_request * dreq

  -- undescribed --

ea_list * e

  attribute to be dumped

### Description

ea_dump() dumps contents of the extended attribute given to the debug output.

### Function

uint ea_hash (ea_list * e) -- calculate an ea_list hash key

### Arguments

ea_list * e

  attribute list

### Description

ea_hash() takes an extended attribute list and calculated a hopefully uniformly distributed hash value from its contents.

### Function

ea_list * ea_append (ea_list * to, ea_list * what) -- concatenate ea_list's

### Arguments

ea_list * to

  destination list (can be NULL)

ea_list * what

  list to be appended (can be NULL)

### Description

This function appends the ea_list what at the end of ea_list to and returns a pointer to the resulting list.

## 2.4 Route attribute storage

While local procesing of routes is done on local structures, the attributes have to be stored to a global data structure to have sufficient lifetime. The global storage also serves deduplication purposes, i.e. when an identical attribute set is about to be stored, an existing structure is returned instead.

All the globally-stored attribute sets have the attributes sorted by ID.

The public interface consists of:

- ea_lookup() to get the global instance of the given attribute list, or to bump its usecount - ea_free() to decrease the instance's usecount, with possibly delayed free - ea_lookup_tmp() to do ea_lookup() with ea_free() auto-called after the end of the task

There are also several low-level interface functions and helpers.

There may be attributes which need to recursively refer to another attribute set. These attributes must have `stored` and `freed` hooks of their `struct ea_class` defined.

Description of the data structure follows; more detailed information is directly in the code.

************************************** Internal structure of route storage * **************************************

Attribute lists, publicly available as `ea_list`, are stored as `ea_storage` which contains the `ea_list` and adds storage-private data. One should not access the `ea_storage` from `ea_list`, and definitely not change it.

These `struct ea_storage` objects are arranged in a hash array (array of linked lists) stored in the `rta_hash` table. This table gets automatically rehashed by ea_rehash() whenever needed.

The usecounts of `ea_storage` must be kept at 1 at all times. Whenever the usecount reaches zero, it must not be increased again and the `ea_storage` is waiting for free.

There are two `ea_hash_array`s which are used to allow rehashing without hard locking. These are switched atomically when the rehash is done. Rehash awareness is required for reasonable lockless lookup and free.

********* Lookup * *********

The lookup function always checks whether it can return an already existing structure containing the same data. Therefore, after normalizing the attribute set contents, it calculates a hash value from its whole content, and looks into the hash array.

If an entry is already there, the existing structure is returned, otherwise a new structure is allocated and put there.

That would work in one thread though. We need thread-safe operation and lockless collision resolution. With that, the hash chain pass is done as RCU critical section, and we can't do time-consuming operations during that. Even though in most cases, mslab allocation is waitless (threads have pre-allocated objects), we may still end up doing a syscall during allocation (mmap), and that's not acceptable. Also very large objects (over 1.3k) use mutexes when allocating.

Therefore, we do multiple passes. In the zeroth pass, we check for en existing entry. If it is already there, the situation is the easiest, we can just use that, and spare the allocation.

Otherwise, we allocate the entry and run another pass. It may have happened that another thread has just done exactly the same, and we may end up re-using that entry. In such case, we simply refcount that, and de-allocate our version. Otherwise, we put the item into the chain.

But we may have run into a collision again with somebody putting their item into the chain. That is unfortunate, and therefore we try pass 2, with the same objective as with pass 1: check for collisions, insert.

We are not infinitely patient though, and on the pass 3, if we encounter a collision again, we stop checking the chain and just insert the entry. That may lead to deduplication, and therefore we issue a warning in such case. While developing and stress testing, we have never managed to actually trigger it.

Note: There may be situations where we encounter an entry which is about to be removed. We ignore these entries.

************ Use count * ************

The entries are use-counted. That is an easy way to track their lifetimes but it brings another catch. What if one thread tries to insert an entry at the same time as another thread is deleting it?

First, we would like to refuse to increase usecounts which are already zero. That is not so easy though. The easy approach would be that both lookup and free first fetch the count, locally increment/decrement, and then they try to atomically exchange it for the previous value.

Yet, when these collide, the cache gets invalidated over and over again, and in our measurements, the allocation times were severely hampered by waiting for the usecount update.

While the allocations are scattered quite randomly all around the time in locked contexts of various degrees, free is by default deferred to the end of the task, almost always happens in batches, and does not hold any additional lock. Therefore, we want to speed up allocations.

**************************** Free: Marking for removal * ****************************

The whole entry removal ordeal begins with lowering the usecount, and if we are lucky, it is still more than one.

If the usecount becomes zero, the hard time starts. It may have been so that the allocator has just found this entry, and raised the usecount again. While we could, in the allocator, first read the usecount and then decide, it's slow (see above). Instead, the allocator just comes, increments, and is done (almost).

The allocator also can't simply check for zero usecount after the increment. While that may be seen by the allocator, another allocating thread may have come just after that, seen `uc == 1`, and considered the entry proper again. Or even worse, there may be multiple threads serializing in the most peculiar ways.

Therefore, we need a flag. Whenever the usecount becomes zero, the thread subsequently tries to atomically replace that zero by `EA_FREE_FLAG`, which is a very high value reserved for an entry which is about to be removed from the chain. Suddenly, either at least one of the allocating threads has serialized before this, and therefore the zero replacement fails (because the entry has been revived), or they serialize after the exchange, and they now see the flag, and can back off.

As soon as the entry is successfully flagged, it can be safely removed from the chain.

***************************************** Free: Actually removing from the chain * *****************************************

Chain removal is not safe when multiple threads are removing at once, and there is a well-known race condition between two linked-list deleters, mistakenly reviving an item. Therefore we need to avoid multiple deleters running in parallel. Also, to delete an item, one has to walk the chain from the beginning, to find the ancestor.

There is a parallel atomic integer array `delist`, which has an entry for every chain in the table. That entry is a hybrid semaphore-spinlock.

Every deleter increments the appropriate `delist` entry when it's about to remove an item from a chain. The first one wins the cleanup job, starts walking the chain and removing items. All other deleters find out that the cleaner is running right now, and they just let go.

The removal is just pointer manipulation, and it does not collide with allocation, with the exception of the very first entry in the list, where it may cause an additional lookup pass.

When the cleaner is done with removing one item, it decrements the `delist` entry but it continues with removing more entries until the entry is zero again. This loop could, theoretically, be infinite, but considering the workload characteristics, it's very improbable.

There could be also a race condition where another cleaner marks an entry for deletion, and the cleaner removes that from the chain before the `delist` counter could get incremented. However, that means that there was another deletion pending, and the cleaner just picked the new one.

If the cleaner ends before all finished entries are removed from the chain, it must have been caused by some other threads not yet incrementing the `delist` counter, and one of them will inevitably become the new cleaner, keeping the balance.

******************************** Free: Deallocating the memory * ********************************

We must not immediately return the memory block to the mslab, that would be a gross negligence punishable by segfault. Even though the entry has been removed from the list, there may still be an allocator thread holding a pointer to that, sleeping just before checking the usecount (where it would find out that it is indeed bad and ultimately retry).

We could simply call synchronize_rcu() to actively wait until all these sleeping threads get flushed but that adds a lot of overhead when freeing hundreds of thousands of routes at once. Instead, we collect these items into a defer call structure, storing the current RCU phase with them, and only after all the chain removals are done, the deferred call waits for RCU synchronization once for all removed entries.

Then, and only then, are the entries returned to the mslab.

************ Rehashing * ************

Hold on a minute. The hash array is not constantly sized, and it must grow with the amount of actually stored entries. Therefore, all the operations keep track of the number of items inside the whole structure, and whenever the total amount gets over or under certain threshold, the hash array grows or shrinks.

The rehash does not lock. Instead, it double-uses the already existing mechanisms to avoid collisions. The only locking mechanism it uses, is the fixation of this task into the main thread, making it impossible to collide two rehashes at once.

First, it allocates all the new structures aside, and initializes them. Most notably, it initializes all the new `delist` entries to 1. The fully initialized `ea_hash_array` is then atomically released, with RCU synchronization to flush all previous readers before actually starting the rehash procedure.

Lookups always check both arrays whenever rehash is running, and they always add entries to the new one. And free is even easier -- if freeing from a not-yet-rehashed chain, it sees `delist` initialized to 1, and backs off. The rehash routine then simply drops all obsolete entries when rehashing.

### Function

ea_list * ea_lookup_slow (ea_list * o, u32 squash_upto, enum ea_stored oid) -- find and reference the given ea_list

### Arguments

ea_list * o

  list to insert

u32 squash_upto

  storage levels to stop where squashing (bitmask)

enum ea_stored oid

  the storage level of this ea_list

### Description

Expects a locally-allocated ea_list, possibly with multiple layers, possibly atop another already cached ea_list. Performs normalization, squashing and cache lookup.

Returns a globally-available ea_list object with a use count already incremented. The caller must subsequently explicitly call ea_free() to unreference the object.

### Function

void ea_free_deferred (struct deferred_call * dc) -- defer callback to process unreferencing of ea_storage

### Arguments

struct deferred_call * dc

  the deferred call

### Description

This callback is scheduled by ea_free() and ea_free_later(), to use-uncount one `ea_storage`. The callback runs as a deferred call to ensure that the user may actually get an easy reference with task-local lifetime.

### Function

void ea_dump_all (struct dump_request * dreq) -- dump attribute cache

### Arguments

struct dump_request * dreq

  -- undescribed --

### Description

This function dumps the whole contents of route attribute cache to the debug output.

### Function

void rta_init (void) -- initialize route attribute cache

### Description

This function is called during initialization of the routing table module to set up the internals of the attribute cache.

### Function

rta * rta_clone (rta * r) -- clone route attributes

### Arguments

rta * r

  a rta to be cloned

### Description

rta_clone() takes a cached rta and returns its identical cached copy. Currently it works by just returning the original rta with its use count incremented.

### Function

void rta_free (rta * r) -- free route attributes

### Arguments

rta * r

  a rta to be freed

### Description

If you stop using a rta (for example when deleting a route which uses it), you need to call rta_free() to notify the attribute cache the attribute is no longer in use and can be freed if you were the last user (which rta_free() tests by inspecting the use count).

## 2.5 Routing protocols

### Introduction

The routing protocols are the bird's heart and a fine amount of code is dedicated to their management and for providing support functions to them. (-: Actually, this is the reason why the directory with sources of the core code is called `nest` :-).

When talking about protocols, one need to distinguish between protocols and protocol instances. A protocol exists exactly once, not depending on whether it's configured or not and it can have an arbitrary number of instances corresponding to its "incarnations" requested by the configuration file. Each instance is completely autonomous, has its own configuration, its own status, its own set of routes and its own set of interfaces it works on.

A protocol is represented by a protocol structure containing all the basic information (protocol name, default settings and pointers to most of the protocol hooks). All these structures are linked in the protocol_list list.

Each instance has its own proto structure describing all its properties: protocol type, configuration, a resource pool where all resources belonging to the instance live, various protocol attributes (take a look at the declaration of proto in `protocol.h`), protocol states (see below for what do they mean), connections to routing tables, filters attached to the protocol and finally a set of pointers to the rest of protocol hooks (they are the same for all instances of the protocol, but in order to avoid extra indirections when calling the hooks from the fast path, they are stored directly in proto). The instance is always linked in both the global instance list (proto_list) and a per-status list (either active_proto_list for running protocols, initial_proto_list for protocols being initialized or flush_proto_list when the protocol is being shut down).

The protocol hooks are described in the next chapter, for more information about configuration of protocols, please refer to the configuration chapter and also to the description of the proto_commit function.

### Protocol states

As startup and shutdown of each protocol are complex processes which can be affected by lots of external events (user's actions, reconfigurations, behavior of neighboring routers etc.), we have decided to supervise them by a pair of simple state machines -- the protocol state machine and a core state machine.

The protocol state machine corresponds to internal state of the protocol and the protocol can alter its state whenever it wants to. There are the following states:

`PS_DOWN`

  The protocol is down and waits for being woken up by calling its start() hook.

`PS_START`

  The protocol is waiting for connection with the rest of the network. It's active, it has resources allocated, but it still doesn't want any routes since it doesn't know what to do with them.

`PS_UP`

  The protocol is up and running. It communicates with the core, delivers routes to tables and wants to hear announcement about route changes.

`PS_STOP`

  The protocol has been shut down (either by being asked by the core code to do so or due to having encountered a protocol error).

Unless the protocol is in the `PS_DOWN` state, it can decide to change its state by calling the proto_notify_state function.

At any time, the core code can ask the protocol to shut itself down by calling its stop() hook.

### Functions of the protocol module

The protocol module provides the following functions:

### Function

struct channel * proto_find_channel_by_table (struct proto * p, rtable * t) -- find channel connected to a routing table

### Arguments

struct proto * p

  protocol instance

rtable * t

  routing table

### Description

Returns pointer to channel or NULL

### Function

struct channel * proto_find_channel_by_name (struct proto * p, const char * n) -- find channel by its name

### Arguments

struct proto * p

  protocol instance

const char * n

  channel name

### Description

Returns pointer to channel or NULL

### Function

struct channel * proto_add_channel (struct proto * p, struct channel_config * cf) -- connect protocol to a routing table

### Arguments

struct proto * p

  protocol instance

struct channel_config * cf

  channel configuration

### Description

This function creates a channel between the protocol instance p and the routing table specified in the configuration cf, making the protocol hear all changes in the table and allowing the protocol to update routes in the table.

The channel is linked in the protocol channel list and when active also in the table channel list. Channels are allocated from the global resource pool (proto_pool) and they are automatically freed when the protocol is removed.

### Function

void * proto_new (struct proto_config * cf) -- create a new protocol instance

### Arguments

struct proto_config * cf

  -- undescribed --

### Description

When a new configuration has been read in, the core code starts initializing all the protocol instances configured by calling their init() hooks with the corresponding instance configuration. The initialization code of the protocol is expected to create a new instance according to the configuration by calling this function and then modifying the default settings to values wanted by the protocol.

### Function

void * proto_config_new (struct protocol * pr, int class) -- create a new protocol configuration

### Arguments

struct protocol * pr

  protocol the configuration will belong to

int class

  SYM_PROTO or SYM_TEMPLATE

### Description

Whenever the configuration file says that a new instance of a routing protocol should be created, the parser calls proto_config_new() to create a configuration entry for this instance (a structure staring with the proto_config header containing all the generic items followed by protocol-specific ones). Also, the configuration entry gets added to the list of protocol instances kept in the configuration.

The function is also used to create protocol templates (when class SYM_TEMPLATE is specified), the only difference is that templates are not added to the list of protocol instances and therefore not initialized during protos_commit()).

### Function

void proto_copy_config (struct proto_config * dest, struct proto_config * src) -- copy a protocol configuration

### Arguments

struct proto_config * dest

  destination protocol configuration

struct proto_config * src

  source protocol configuration

### Description

Whenever a new instance of a routing protocol is created from the template, proto_copy_config() is called to copy a content of the source protocol configuration to the new protocol configuration. Name, class and a node in protos list of dest are kept intact. copy_config() protocol hook is used to copy protocol-specific data.

### Function

void protos_preconfig (struct config * c) -- pre-configuration processing

### Arguments

struct config * c

  new configuration

### Description

This function calls the preconfig() hooks of all routing protocols available to prepare them for reading of the new configuration.

### Function

void protos_commit (struct config * new, struct config * old, int type) -- commit new protocol configuration

### Arguments

struct config * new

  new configuration

struct config * old

  old configuration or NULL if it's boot time config

int type

  type of reconfiguration (RECONFIG_SOFT or RECONFIG_HARD)

### Description

Scan differences between old and new configuration and adjust all protocol instances to conform to the new configuration.

When a protocol exists in the new configuration, but it doesn't in the original one, it's immediately started. When a collision with the other running protocol would arise, the new protocol will be temporarily stopped by the locking mechanism.

When a protocol exists in the old configuration, but it doesn't in the new one, it's shut down and deleted after the shutdown completes.

When a protocol exists in both configurations, the core decides whether it's possible to reconfigure it dynamically - it checks all the core properties of the protocol (changes in filters are ignored if type is RECONFIG_SOFT) and if they match, it asks the reconfigure() hook of the protocol to see if the protocol is able to switch to the new configuration. If it isn't possible, the protocol is shut down and a new instance is started with the new configuration after the shutdown is completed.

## 2.6 Graceful restart recovery

Graceful restart of a router is a process when the routing plane (e.g. BIRD) restarts but both the forwarding plane (e.g kernel routing table) and routing neighbors keep proper routes, and therefore uninterrupted packet forwarding is maintained.

BIRD implements graceful restart recovery by deferring export of routes to protocols until routing tables are refilled with the expected content. After start, protocols generate routes as usual, but routes are not propagated to them, until protocols report that they generated all routes. After that, graceful restart recovery is finished and the export (and the initial feed) to protocols is enabled.

When graceful restart recovery need is detected during initialization, then enabled protocols are marked with gr_recovery flag before start. Such protocols then decide how to proceed with graceful restart, participation is voluntary. Protocols could lock the recovery for each channel by function channel_graceful_restart_lock() (state stored in gr_lock flag), which means that they want to postpone the end of the recovery until they converge and then unlock it. They also could set gr_wait before advancing to PS_UP, which means that the core should defer route export to that channel until the end of the recovery. This should be done by protocols that expect their neigbors to keep the proper routes (kernel table, BGP sessions with BGP graceful restart capability).

The graceful restart recovery is finished when either all graceful restart locks are unlocked or when graceful restart wait timer fires.

### Function

void graceful_recovery_done (struct callback *_ UNUSED) -- finalize graceful restart

### Arguments

struct callback *_ UNUSED

  -- undescribed --

### Description

When there are no locks on graceful restart, the functions finalizes the graceful restart recovery. Protocols postponing route export until the end of the recovery are awakened and the export to them is enabled.

### Function

void graceful_restart_recovery (void) -- request initial graceful restart recovery

### Description

Called by the platform initialization code if the need for recovery after graceful restart is detected during boot. Have to be called before protos_commit().

### Function

void graceful_restart_init (void) -- initialize graceful restart

### Description

When graceful restart recovery was requested, the function starts an active phase of the recovery and initializes graceful restart wait timer. The function have to be called after protos_commit().

### Function

void channel_graceful_restart_lock (struct channel * c) -- lock graceful restart by channel

### Arguments

struct channel * c

  -- undescribed --

### Description

This function allows a protocol to postpone the end of graceful restart recovery until it converges. The lock is removed when the protocol calls channel_graceful_restart_unlock() or when the channel is closed.

The function have to be called during the initial phase of graceful restart recovery and only for protocols that are part of graceful restart (i.e. their gr_recovery is set), which means it should be called from protocol start hooks.

### Function

void channel_graceful_restart_unlock (struct channel * c) -- unlock graceful restart by channel

### Arguments

struct channel * c

  -- undescribed --

### Description

This function unlocks a lock from channel_graceful_restart_lock(). It is also automatically called when the lock holding protocol went down.

### Function

void protos_dump_all (struct dump_request * dreq) -- dump status of all protocols

### Arguments

struct dump_request * dreq

  -- undescribed --

### Description

This function dumps status of all existing protocol instances to the debug output. It involves printing of general status information such as protocol states, its position on the protocol lists and also calling of a dump() hook of the protocol to print the internals.

### Function

void proto_build (struct protocol * p) -- make a single protocol available

### Arguments

struct protocol * p

  the protocol

### Description

After the platform specific initialization code uses protos_build() to add all the standard protocols, it should call proto_build() for all platform specific protocols to inform the core that they exist.

### Function

void protos_build (void) -- build a protocol list

### Description

This function is called during BIRD startup to insert all standard protocols to the global protocol list. Insertion of platform specific protocols (such as the kernel syncer) is in the domain of competence of the platform dependent startup code.

### Function

void proto_set_message (struct proto * p, char * msg, int len) -- set administrative message to protocol

### Arguments

struct proto * p

  protocol

char * msg

  message

int len

  message length (-1 for NULL-terminated string)

### Description

The function sets administrative message (string) related to protocol state change. It is called by the nest code for manual enable/disable/restart commands all routes to the protocol, and by protocol-specific code when the protocol state change is initiated by the protocol. Using NULL message clears the last message. The message string may be either NULL-terminated or with an explicit length.

### Function

void proto_notify_state (struct proto * p, uint state) -- notify core about protocol state change

### Arguments

struct proto * p

  protocol the state of which has changed

uint state

  -- undescribed --

### Description

Whenever a state of a protocol changes due to some event internal to the protocol (i.e., not inside a start() or shutdown() hook), it should immediately notify the core about the change by calling proto_notify_state() which will write the new state to the proto structure and take all the actions necessary to adapt to the new state. State change to PS_DOWN immediately frees resources of protocol and might execute start callback of protocol; therefore, it should be used at tail positions of protocol callbacks.

## 2.7 Protocol hooks

Each protocol can provide a rich set of hook functions referred to by pointers in either the proto or protocol structure. They are called by the core whenever it wants the protocol to perform some action or to notify the protocol about any change of its environment. All of the hooks can be set to NULL which means to ignore the change or to take a default action.

### Function

void preconfig (struct protocol * p, struct config * c) -- protocol preconfiguration

### Arguments

struct protocol * p

  a routing protocol

struct config * c

  new configuration

### Description

The preconfig() hook is called before parsing of a new configuration.

### Function

void postconfig (struct proto_config * c) -- instance post-configuration

### Arguments

struct proto_config * c

  instance configuration

### Description

The postconfig() hook is called for each configured instance after parsing of the new configuration is finished.

### Function

struct proto * init (struct proto_config * c) -- initialize an instance

### Arguments

struct proto_config * c

  instance configuration

### Description

The init() hook is called by the core to create a protocol instance according to supplied protocol configuration.

### Result

a pointer to the instance created

### Function

int reconfigure (struct proto * p, struct proto_config * c) -- request instance reconfiguration

### Arguments

struct proto * p

  an instance

struct proto_config * c

  new configuration

### Description

The core calls the reconfigure() hook whenever it wants to ask the protocol for switching to a new configuration. If the reconfiguration is possible, the hook returns 1. Otherwise, it returns 0 and the core will shut down the instance and start a new one with the new configuration.

After the protocol confirms reconfiguration, it must no longer keep any references to the old configuration since the memory it's stored in can be re-used at any time.

### Function

void dump (struct proto * p) -- dump protocol state

### Arguments

struct proto * p

  an instance

### Description

This hook dumps the complete state of the instance to the debug output.

### Function

int start (struct proto * p) -- request instance startup

### Arguments

struct proto * p

  protocol instance

### Description

The start() hook is called by the core when it wishes to start the instance. Multitable protocols should lock their tables here.

### Result

new protocol state

### Function

int shutdown (struct proto * p) -- request instance shutdown

### Arguments

struct proto * p

  protocol instance

### Description

The stop() hook is called by the core when it wishes to shut the instance down for some reason.

### Returns

new protocol state

### Function

void cleanup (struct proto * p) -- request instance cleanup

### Arguments

struct proto * p

  protocol instance

### Description

The cleanup() hook is called by the core when the protocol became hungry/down, i.e. all protocol ahooks and routes are flushed. Multitable protocols should unlock their tables here.

### Function

void get_status (struct proto * p, byte * buf) -- get instance status

### Arguments

struct proto * p

  protocol instance

byte * buf

  buffer to be filled with the status string

### Description

This hook is called by the core if it wishes to obtain an brief one-line user friendly representation of the status of the instance to be printed by the <cf/show protocols/ command.

### Function

void get_route_info (rte * e, byte * buf, ea_list * attrs) -- get route information

### Arguments

rte * e

  a route entry

byte * buf

  buffer to be filled with the resulting string

ea_list * attrs

  extended attributes of the route

### Description

This hook is called to fill the buffer buf with a brief user friendly representation of metrics of a route belonging to this protocol.

### Function

int get_attr (eattr * a, byte * buf, int buflen) -- get attribute information

### Arguments

eattr * a

  an extended attribute

byte * buf

  buffer to be filled with attribute information

int buflen

  a length of the buf parameter

### Description

The get_attr() hook is called by the core to obtain a user friendly representation of an extended route attribute. It can either leave the whole conversion to the core (by returning GA_UNKNOWN), fill in only attribute name (and let the core format the attribute value automatically according to the type field; by returning GA_NAME) or doing the whole conversion (used in case the value requires extra care; return GA_FULL).

### Function

void if_notify (struct proto * p, unsigned flags, struct iface * i) -- notify instance about interface changes

### Arguments

struct proto * p

  protocol instance

unsigned flags

  interface change flags

struct iface * i

  the interface in question

### Description

This hook is called whenever any network interface changes its status. The change is described by a combination of status bits (IF_CHANGE_xxx) in the flags parameter.

### Function

void ifa_notify (struct proto * p, unsigned flags, struct ifa * a) -- notify instance about interface address changes

### Arguments

struct proto * p

  protocol instance

unsigned flags

  address change flags

struct ifa * a

  the interface address

### Description

This hook is called to notify the protocol instance about an interface acquiring or losing one of its addresses. The change is described by a combination of status bits (IF_CHANGE_xxx) in the flags parameter.

### Function

void rt_notify (struct proto * p, net * net, rte * new, rte * old, ea_list * attrs) -- notify instance about routing table change

### Arguments

struct proto * p

  protocol instance

net * net

  a network entry

rte * new

  new route for the network

rte * old

  old route for the network

ea_list * attrs

  extended attributes associated with the new entry

### Description

The rt_notify() hook is called to inform the protocol instance about changes in the connected routing table table, that is a route old belonging to network net being replaced by a new route new with extended attributes attrs. Either new or old or both can be NULL if the corresponding route doesn't exist.

If the type of route announcement is RA_OPTIMAL, it is an announcement of optimal route change, new stores the new optimal route and old stores the old optimal route.

If the type of route announcement is RA_ANY, it is an announcement of any route change, new stores the new route and old stores the old route from the same protocol.

p->accept_ra_types specifies which kind of route announcements protocol wants to receive.

### Function

void neigh_notify (neighbor * neigh) -- notify instance about neighbor status change

### Arguments

neighbor * neigh

  a neighbor cache entry

### Description

The neigh_notify() hook is called by the neighbor cache whenever a neighbor changes its state, that is it gets disconnected or a sticky neighbor gets connected.

### Function

int preexport (struct proto * p, rte ** e, ea_list ** attrs, struct linpool * pool) -- pre-filtering decisions before route export

### Arguments

struct proto * p

  protocol instance the route is going to be exported to

rte ** e

  the route in question

ea_list ** attrs

  extended attributes of the route

struct linpool * pool

  linear pool for allocation of all temporary data

### Description

The preexport() hook is called as the first step of a exporting a route from a routing table to the protocol instance. It can modify route attributes and force acceptance or rejection of the route before the user-specified filters are run. See rte_announce() for a complete description of the route distribution process.

The standard use of this hook is to reject routes having originated from the same instance and to set default values of the protocol's metrics.

### Result

1 if the route has to be accepted, -1 if rejected and 0 if it should be passed to the filters.

### Function

int rte_recalculate (struct rtable * table, struct network * net, struct rte * new, struct rte * old, struct rte * old_best) -- prepare routes for comparison

### Arguments

struct rtable * table

  a routing table

struct network * net

  a network entry

struct rte * new

  new route for the network

struct rte * old

  old route for the network

struct rte * old_best

  old best route for the network (may be NULL)

### Description

This hook is called when a route change (from old to new for a net entry) is propagated to a table. It may be used to prepare routes for comparison by rte_better() in the best route selection. new may or may not be in net->routes list, old is not there.

### Result

1 if the ordering implied by rte_better() changes enough that full best route calculation have to be done, 0 otherwise.

### Function

int rte_better (rte * new, rte * old) -- compare metrics of two routes

### Arguments

rte * new

  the new route

rte * old

  the original route

### Description

This hook gets called when the routing table contains two routes for the same network which have originated from different instances of a single protocol and it wants to select which one is preferred over the other one. Protocols usually decide according to route metrics.

### Result

1 if new is better (more preferred) than old, 0 otherwise.

### Function

int rte_same (rte * e1, rte * e2) -- compare two routes

### Arguments

rte * e1

  route

rte * e2

  route

### Description

The rte_same() hook tests whether the routes e1 and e2 belonging to the same protocol instance have identical contents. Contents of rta, all the extended attributes and rte preference are checked by the core code, no need to take care of them here.

### Result

1 if e1 is identical to e2, 0 otherwise.

### Function

void rte_insert (net * n, rte * e) -- notify instance about route insertion

### Arguments

net * n

  network

rte * e

  route

### Description

This hook is called whenever a rte belonging to the instance is accepted for insertion to a routing table.

Please avoid using this function in new protocols.

### Function

void rte_remove (net * n, rte * e) -- notify instance about route removal

### Arguments

net * n

  network

rte * e

  route

### Description

This hook is called whenever a rte belonging to the instance is removed from a routing table.

Please avoid using this function in new protocols.

## 2.8 Interfaces

The interface module keeps track of all network interfaces in the system and their addresses.

Each interface is represented by an iface structure which carries interface capability flags (IF_MULTIACCESS, IF_BROADCAST etc.), MTU, interface name and index and finally a linked list of network prefixes assigned to the interface, each one represented by struct ifa.

The interface module keeps a `soft-up' state for each iface which is a conjunction of link being up, the interface being of a `sane' type and at least one IP address assigned to it.

### Function

void ifa_dump (struct dump_request * dreq, struct ifa * a) -- dump interface address

### Arguments

struct dump_request * dreq

  -- undescribed --

struct ifa * a

  interface address descriptor

### Description

This function dumps contents of an ifa to the debug output.

### Function

void if_dump (struct dump_request * dreq, struct iface * i) -- dump interface

### Arguments

struct dump_request * dreq

  -- undescribed --

struct iface * i

  interface to dump

### Description

This function dumps all information associated with a given network interface to the debug output.

### Function

void if_dump_all (struct dump_request * dreq) -- dump all interfaces

### Arguments

struct dump_request * dreq

  -- undescribed --

### Description

This function dumps information about all known network interfaces to the debug output.

### Function

void if_delete (struct iface * old) -- remove interface

### Arguments

struct iface * old

  interface

### Description

This function is called by the low-level platform dependent code whenever it notices an interface disappears. It is just a shorthand for if_update().

### Function

struct iface * if_update (struct iface * new) -- update interface status

### Arguments

struct iface * new

  new interface status

### Description

if_update() is called by the low-level platform dependent code whenever it notices an interface change.

There exist two types of interface updates -- synchronous and asynchronous ones. In the synchronous case, the low-level code calls if_start_update(), scans all interfaces reported by the OS, uses if_update() and ifa_update() to pass them to the core and then it finishes the update sequence by calling if_end_update(). When working asynchronously, the sysdep code calls if_update() and ifa_update() whenever it notices a change.

if_update() will automatically notify all other modules about the change.

### Function

void iface_subscribe (struct iface_subscription * s) -- request interface updates

### Arguments

struct iface_subscription * s

  subscription structure

### Description

When a new protocol starts, this function sends it a series of notifications about all existing interfaces.

### Function

void iface_unsubscribe (struct iface_subscription * s) -- unsubscribe from interface updates

### Arguments

struct iface_subscription * s

  subscription structure

### Function

struct iface * if_find_by_index_locked (unsigned idx) -- find interface by ifindex

### Arguments

unsigned idx

  ifindex

### Description

This function finds an iface structure corresponding to an interface of the given index idx. Returns a pointer to the structure or NULL if no such structure exists.

### Function

struct iface * if_find_by_name (const char * name) -- find interface by name

### Arguments

const char * name

  interface name

### Description

This function finds an iface structure corresponding to an interface of the given name name. Returns a pointer to the structure or NULL if no such structure exists.

### Function

struct ifa * ifa_update (struct ifa * a) -- update interface address

### Arguments

struct ifa * a

  new interface address

### Description

This function adds address information to a network interface. It's called by the platform dependent code during the interface update process described under if_update().

### Function

void ifa_delete (struct ifa * a) -- remove interface address

### Arguments

struct ifa * a

  interface address

### Description

This function removes address information from a network interface. It's called by the platform dependent code during the interface update process described under if_update().

### Function

void if_init (void) -- initialize interface module

### Description

This function is called during BIRD startup to initialize all data structures of the interface module.

## 2.9 MPLS

The MPLS subsystem manages MPLS labels and handles their allocation to MPLS-aware routing protocols. These labels are then attached to IP or VPN routes representing label switched paths -- LSPs. MPLS labels are also used in special MPLS routes (which use labels as network address) that are exported to MPLS routing table in kernel. The MPLS subsystem consists of MPLS domains (struct mpls_domain), MPLS channels (struct mpls_channel) and FEC maps (struct mpls_fec_map).

The MPLS domain represents one MPLS label address space, implements the label allocator, and handles associated configuration and management. The domain is declared in the configuration (struct mpls_domain_config). There might be multiple MPLS domains representing separate label spaces, but in most cases one domain is enough. MPLS-aware protocols and routing tables are associated with a specific MPLS domain.

The MPLS domain has configurable label ranges (struct mpls_range), by default it has two ranges: static (16-1000) and dynamic (1000-10000). When a protocol wants to allocate labels, it first acquires a handle (struct mpls_handle) for a specific range using mpls_new_handle(), and then it allocates labels from that with mpls_new_label(). When not needed, labels are freed by mpls_free_label() and the handle is released by mpls_free_handle(). Note that all labels and handles must be freed manually.

Both MPLS domain and MPLS range are reference counted, so when deconfigured they could be freed just after all labels and ranges are freed. Users are expected to hold a reference to a MPLS domain for whole time they use something from that domain (e.g. mpls_handle), but releasing reference to a range while holding associated handle is OK.

The MPLS channel is subclass of a generic protocol channel. It has two distinct purposes - to handle per-protocol MPLS configuration (e.g. which MPLS domain is associated with the protocol, which label range is used by the protocol), and to announce MPLS routes to a routing table (as a regular protocol channel).

The FEC map is a helper structure that maps forwarding equivalent classes (FECs) to MPLS labels. It is an internal matter of a routing protocol how to assign meaning to allocated labels, announce LSP routes and associated MPLS routes (i.e. ILM entries). But the common behavior is implemented in the FEC map, which can be used by the protocols that work with IP-prefix-based FECs.

The FEC map keeps hash tables of FECs (struct mpls_fec) based on network prefix, next hop eattr and assigned label. It has three general labeling policies: static assignment (MPLS_POLICY_STATIC), per-prefix policy (MPLS_POLICY_PREFIX), and aggregating policy (MPLS_POLICY_AGGREGATE). In per-prefix policy, each distinct LSP is a separate FEC and uses a separate label, which is kept even if the next hop of the LSP changes. In aggregating policy, LSPs with a same next hop form one FEC and use one label, but when a next hop (or remote label) of such LSP changes then the LSP must be moved to a different FEC and assigned a different label. There is also a special VRF policy (MPLS_POLICY_VRF) applicable for L3VPN protocols, which uses one label for all routes from a VRF, while replacing the original next hop with lookup in the VRF.

The overall process works this way: A protocol wants to announce a LSP route, it does that by announcing e.g. IP route with EA_MPLS_POLICY attribute. After the route is accepted by filters (which may also change the policy attribute or set a static label), the mpls_handle_rte() is called from rte_update2(), which applies selected labeling policy, finds existing FEC or creates a new FEC (which includes allocating new label and announcing related MPLS route by mpls_announce_fec()), and attach FEC label to the LSP route. After that, the LSP route is stored in routing table by rte_recalculate(). Changes in routing tables trigger mpls_rte_insert() and mpls_rte_remove() hooks, which refcount FEC structures and possibly trigger removal of FECs and withdrawal of MPLS routes.

TODO: - special handling of reserved labels

## 2.10 Neighbor cache

Most routing protocols need to associate their internal state data with neighboring routers, check whether an address given as the next hop attribute of a route is really an address of a directly connected host and which interface is it connected through. Also, they often need to be notified when a neighbor ceases to exist or when their long awaited neighbor becomes connected. The neighbor cache is there to solve all these problems.

The neighbor cache maintains a collection of neighbor entries. Each entry represents one IP address corresponding to either our directly connected neighbor or our own end of the link (when the scope of the address is set to SCOPE_HOST) together with per-neighbor data belonging to a single protocol. A neighbor entry may be bound to a specific interface, which is required for link-local IP addresses and optional for global IP addresses.

Neighbor cache entries are stored in a hash table, which is indexed by triple (protocol, IP, requested-iface), so if both regular and iface-bound neighbors are requested, they are represented by two neighbor cache entries. Active entries are also linked in per-interface list (allowing quick processing of interface change events). Inactive entries exist only when the protocol has explicitly requested it via the NEF_STICKY flag because it wishes to be notified when the node will again become a neighbor. Such entries are instead linked in a special list, which is walked whenever an interface changes its state to up. Neighbor entry VRF association is implied by respective protocol.

Besides the already mentioned NEF_STICKY flag, there is also NEF_ONLINK, which specifies that neighbor should be considered reachable on given iface regardless of associated address ranges, and NEF_IFACE, which represents pseudo-neighbor entry for whole interface (and uses IPA_NONE IP address).

When a neighbor event occurs (a neighbor gets disconnected or a sticky inactive neighbor becomes connected), the protocol hook neigh_notify() is called to advertise the change.

### Function

neighbor * neigh_find (struct proto * p, ip_addr a, struct iface * iface, uint flags) -- find or create a neighbor entry

### Arguments

struct proto * p

  protocol which asks for the entry

ip_addr a

  IP address of the node to be searched for

struct iface * iface

  optionally bound neighbor to this iface (may be NULL)

uint flags

  NEF_STICKY for sticky entry, NEF_ONLINK for onlink entry

### Description

Search the neighbor cache for a node with given IP address. Iface can be specified for link-local addresses or for cases, where neighbor is expected on given interface. If it is found, a pointer to the neighbor entry is returned. If no such entry exists and the node is directly connected on one of our active interfaces, a new entry is created and returned to the caller with protocol-dependent fields initialized to zero. If the node is not connected directly or *a is not a valid unicast IP address, neigh_find() returns NULL.

### Function

void neigh_dump (struct dump_request * dreq, neighbor * n) -- dump specified neighbor entry.

### Arguments

struct dump_request * dreq

  -- undescribed --

neighbor * n

  the entry to dump

### Description

This functions dumps the contents of a given neighbor entry to debug output.

### Function

void neigh_dump_all (struct dump_request * dreq) -- dump all neighbor entries.

### Arguments

struct dump_request * dreq

  -- undescribed --

### Description

This function dumps the contents of the neighbor cache to debug output.

### Function

void neigh_update (neighbor * n, struct iface * iface)

### Arguments

neighbor * n

  neighbor to update

struct iface * iface

  changed iface

### Description

The function recalculates state of the neighbor entry n assuming that only the interface iface may changed its state or addresses. Then, appropriate actions are executed (the neighbor goes up, down, up-down, or just notified).

### Function

void neigh_if_up (struct iface * i)

### Arguments

struct iface * i

  interface in question

### Description

Tell the neighbor cache that a new interface became up.

The neighbor cache wakes up all inactive sticky neighbors with addresses belonging to prefixes of the interface i.

### Function

void neigh_if_down (struct iface * i) -- notify neighbor cache about interface down event

### Arguments

struct iface * i

  the interface in question

### Description

Notify the neighbor cache that an interface has ceased to exist.

It causes all neighbors connected to this interface to be updated or removed.

### Function

void neigh_if_link (struct iface * i) -- notify neighbor cache about interface link change

### Arguments

struct iface * i

  the interface in question

### Description

Notify the neighbor cache that an interface changed link state. All owners of neighbor entries connected to this interface are notified.

### Function

void neigh_ifa_up (struct ifa * a)

### Arguments

struct ifa * a

  interface address in question

### Description

Tell the neighbor cache that an address was added or removed.

The neighbor cache wakes up all inactive sticky neighbors with addresses belonging to prefixes of the interface belonging to ifa and causes all unreachable neighbors to be flushed.

### Function

void neigh_init (pool * if_pool) -- initialize the neighbor cache.

### Arguments

pool * if_pool

  resource pool to be used for neighbor entries.

### Description

This function is called during BIRD startup to initialize the neighbor cache module.

## 2.11 Command line interface

This module takes care of the BIRD's command-line interface (CLI). The CLI exists to provide a way to control BIRD remotely and to inspect its status. It uses a very simple textual protocol over a stream connection provided by the platform dependent code (on UNIX systems, it's a UNIX domain socket).

Each session of the CLI consists of a sequence of request and replies, slightly resembling the FTP and SMTP protocols. Requests are commands encoded as a single line of text, replies are sequences of lines starting with a four-digit code followed by either a space (if it's the last line of the reply) or a minus sign (when the reply is going to continue with the next line), the rest of the line contains a textual message semantics of which depends on the numeric code. If a reply line has the same code as the previous one and it's a continuation line, the whole prefix can be replaced by a single white space character.

Reply codes starting with 0 stand for `action successfully completed' messages, 1 means `table entry', 8 `runtime error' and 9 `syntax error'.

Each CLI session is internally represented by a cli structure and a resource pool containing all resources associated with the connection, so that it can be easily freed whenever the connection gets closed, not depending on the current state of command processing.

The CLI commands are declared as a part of the configuration grammar by using the `CF_CLI` macro. When a command is received, it is processed by the same lexical analyzer and parser as used for the configuration, but it's switched to a special mode by prepending a fake token to the text, so that it uses only the CLI command rules. Then the parser invokes an execution routine corresponding to the command, which either constructs the whole reply and returns it back or (in case it expects the reply will be long) it prints a partial reply and asks the CLI module (using the cont hook) to call it again when the output is transferred to the user.

The this_cli variable points to a cli structure of the session being currently parsed, but it's of course available only in command handlers not entered using the cont hook.

TX buffer management works as follows: At cli.tx_buf there is a list of TX buffers (struct cli_out), cli.tx_write is the buffer currently used by the producer (cli_printf(), cli_alloc_out()) and cli.tx_pos is the buffer currently used by the consumer (cli_write(), in system dependent code). The producer uses cli_out.wpos ptr as the current write position and the consumer uses cli_out.outpos ptr as the current read position. When the producer produces something, it calls cli_write_trigger(). If there is not enough space in the current buffer, the producer allocates the new one. When the consumer processes everything in the buffer queue, it calls cli_written(), tha frees all buffers (except the first one) and schedules cli.event .

### Function

void cli_vprintf (cli * c, int code, const char * msg, va_list args) -- send reply to a CLI connection

### Arguments

cli * c

  CLI connection

int code

  numeric code of the reply, negative for continuation lines

const char * msg

  a printf()-like formatting string.

va_list args

  -- undescribed --

### Description

This function send a single line of reply to a given CLI connection. In works in all aspects like bsprintf() except that it automatically prepends the reply line prefix.

Please note that if the connection can be already busy sending some data in which case cli_printf() stores the output to a temporary buffer, so please avoid sending a large batch of replies without waiting for the buffers to be flushed.

If you want to write to the current CLI output, you can use the cli_msg() macro instead.

### Function

void cli_init (void) -- initialize the CLI module

### Description

This function is called during BIRD startup to initialize the internal data structures of the CLI module.

## 2.12 Object locks

The lock module provides a simple mechanism for avoiding conflicts between various protocols which would like to use a single physical resource (for example a network port). It would be easy to say that such collisions can occur only when the user specifies an invalid configuration and therefore he deserves to get what he has asked for, but unfortunately they can also arise legitimately when the daemon is reconfigured and there exists (although for a short time period only) an old protocol instance being shut down and a new one willing to start up on the same interface.

The solution is very simple: when any protocol wishes to use a network port or some other non-shareable resource, it asks the core to lock it and it doesn't use the resource until it's notified that it has acquired the lock.

Object locks are represented by object_lock structures which are in turn a kind of resource. Lockable resources are uniquely determined by resource type (OBJLOCK_UDP for a UDP port etc.), IP address (usually a broadcast or multicast address the port is bound to), port number, interface and optional instance ID.

### Function

struct object_lock * olock_new (pool * p) -- create an object lock

### Arguments

pool * p

  resource pool to create the lock in.

### Description

The olock_new() function creates a new resource of type object_lock and returns a pointer to it. After filling in the structure, the caller should call olock_acquire() to do the real locking.

### Function

void olock_acquire (struct object_lock * l) -- acquire a lock

### Arguments

struct object_lock * l

  the lock to acquire

### Description

This function attempts to acquire exclusive access to the non-shareable resource described by the lock l. It returns immediately, but as soon as the resource becomes available, it calls the hook() function set up by the caller.

When you want to release the resource, just rfree() the lock.

### Function

void olock_init (void) -- initialize the object lock mechanism

### Description

This function is called during BIRD startup. It initializes all the internal data structures of the lock module.

Next Previous Contents