BIRD Programmer's Documentation: Protocols

Next Previous Contents

## 5. Protocols

## 5.1 Bidirectional Forwarding Detection

The BFD protocol is implemented in three files: `bfd.c` containing the protocol logic and the protocol glue with BIRD core, `packets.c` handling BFD packet processing, RX, TX and protocol sockets. `io.c` then contains generic code for the event loop, threads and event sources (sockets, microsecond timers). This generic code will be merged to the main BIRD I/O code in the future.

The BFD implementation uses a separate thread with an internal event loop for handling the protocol logic, which requires high-res and low-latency timing, so it is not affected by the rest of BIRD, which has several low-granularity hooks in the main loop, uses second-based timers and cannot offer good latency. The core of BFD protocol (the code related to BFD sessions, interfaces and packets) runs in the BFD thread, while the rest (the code related to BFD requests, BFD neighbors and the protocol glue) runs in the main thread.

BFD sessions are represented by structure bfd_session that contains a state related to the session and two timers (TX timer for periodic packets and hold timer for session timeout). These sessions are allocated from session_slab and are accessible by two hash tables, session_hash_id (by session ID) and session_hash_ip (by IP addresses of neighbors). Slab and both hashes are in the main protocol structure bfd_proto. The protocol logic related to BFD sessions is implemented in internal functions bfd_session_*(), which are expected to be called from the context of BFD thread, and external functions bfd_add_session(), bfd_remove_session() and bfd_reconfigure_session(), which form an interface to the BFD core for the rest and are expected to be called from the context of main thread.

Each BFD session has an associated BFD interface, represented by structure bfd_iface. A BFD interface contains a socket used for TX (the one for RX is shared in bfd_proto), an interface configuration and reference counter. Compared to interface structures of other protocols, these structures are not created and removed based on interface notification events, but according to the needs of BFD sessions. When a new session is created, it requests a proper BFD interface by function bfd_get_iface(), which either finds an existing one in iface_list (from bfd_proto) or allocates a new one. When a session is removed, an associated iface is dicharged by bfd_free_iface().

BFD requests are the external API for the other protocols. When a protocol wants a BFD session, it calls bfd_request_session(), which creates a structure bfd_request containing approprite information and an notify hook. This structure is a resource associated with the caller's resource pool. When a BFD protocol is available, a BFD request is submitted to the protocol, an appropriate BFD session is found or created and the request is attached to the session. When a session changes state, all attached requests (and related protocols) are notified. Note that BFD requests do not depend on BFD protocol running. When the BFD protocol is stopped or removed (or not available from beginning), related BFD requests are stored in bfd_wait_list, where waits for a new protocol.

BFD neighbors are just a way to statically configure BFD sessions without requests from other protocol. Structures bfd_neighbor are part of BFD configuration (like static routes in the static protocol). BFD neighbors are handled by BFD protocol like it is a BFD client -- when a BFD neighbor is ready, the protocol just creates a BFD request like any other protocol.

The protocol uses a new generic event loop (structure birdloop) from `io.c`, which supports sockets, timers and events like the main loop. Timers (structure timer2) are new microsecond based timers, while sockets and events are the same. A birdloop is associated with a thread (field thread) in which event hooks are executed. Most functions for setting event sources (like sk_start() or tm2_start()) must be called from the context of that thread. Birdloop allows to temporarily acquire the context of that thread for the main thread by calling birdloop_enter() and then birdloop_leave(), which also ensures mutual exclusion with all event hooks. Note that resources associated with a birdloop (like timers) should be attached to the independent resource pool, detached from the main resource tree.

There are two kinds of interaction between the BFD core (running in the BFD thread) and the rest of BFD (running in the main thread). The first kind are configuration calls from main thread to the BFD thread (like bfd_add_session()). These calls are synchronous and use birdloop_enter() mechanism for mutual exclusion. The second kind is a notification about session changes from the BFD thread to the main thread. This is done in an asynchronous way, sesions with pending notifications are linked (in the BFD thread) to notify_list in bfd_proto, and then bfd_notify_hook() in the main thread is activated using bfd_notify_kick() and a pipe. The hook then processes scheduled sessions and calls hooks from associated BFD requests. This notify_list (and state fields in structure bfd_session) is protected by a spinlock in bfd_proto and functions bfd_lock_sessions() / bfd_unlock_sessions().

There are few data races (accessing p->p.debug from TRACE() from the BFD thread and accessing some some private fields of bfd_session from bfd_show_sessions() from the main thread, but these are harmless (i hope).

TODO: document functions and access restrictions for fields in BFD structures.

Supported standards: - RFC 5880 - main BFD standard - RFC 5881 - BFD for IP links - RFC 5882 - generic application of BFD - RFC 5883 - BFD for multihop paths

## 5.2 Border Gateway Protocol

The BGP protocol is implemented in three parts: `bgp.c` which takes care of the connection and most of the interface with BIRD core, `packets.c` handling both incoming and outgoing BGP packets and `attrs.c` containing functions for manipulation with BGP attribute lists.

As opposed to the other existing routing daemons, BIRD has a sophisticated core architecture which is able to keep all the information needed by BGP in the primary routing table, therefore no complex data structures like a central BGP table are needed. This increases memory footprint of a BGP router with many connections, but not too much and, which is more important, it makes BGP much easier to implement.

Each instance of BGP (corresponding to a single BGP peer) is described by a bgp_proto structure to which are attached individual connections represented by bgp_connection (usually, there exists only one connection, but during BGP session setup, there can be more of them). The connections are handled according to the BGP state machine defined in the RFC with all the timers and all the parameters configurable.

In incoming direction, we listen on the connection's socket and each time we receive some input, we pass it to bgp_rx(). It decodes packet headers and the markers and passes complete packets to bgp_rx_packet() which distributes the packet according to its type.

In outgoing direction, we gather all the routing updates and sort them to buckets (bgp_bucket) according to their attributes (we keep a hash table for fast comparison of rta's and a fib which helps us to find if we already have another route for the same destination queued for sending, so that we can replace it with the new one immediately instead of sending both updates). There also exists a special bucket holding all the route withdrawals which cannot be queued anywhere else as they don't have any attributes. If we have any packet to send (due to either new routes or the connection tracking code wanting to send a Open, Keepalive or Notification message), we call bgp_schedule_packet() which sets the corresponding bit in a packet_to_send bit field in bgp_conn and as soon as the transmit socket buffer becomes empty, we call bgp_fire_tx(). It inspects state of all the packet type bits and calls the corresponding bgp_create_xx() functions, eventually rescheduling the same packet type if we have more data of the same type to send.

The processing of attributes consists of two functions: bgp_decode_attrs() for checking of the attribute blocks and translating them to the language of BIRD's extended attributes and bgp_encode_attrs() which does the converse. Both functions are built around a bgp_attr_table array describing all important characteristics of all known attributes. Unknown transitive attributes are attached to the route as EAF_TYPE_OPAQUE byte streams.

BGP protocol implements graceful restart in both restarting (local restart) and receiving (neighbor restart) roles. The first is handled mostly by the graceful restart code in the nest, BGP protocol just handles capabilities, sets gr_wait and locks graceful restart until end-of-RIB mark is received. The second is implemented by internal restart of the BGP state to BS_IDLE and protocol state to PS_START, but keeping the protocol up from the core point of view and therefore maintaining received routes. Routing table refresh cycle (rt_refresh_begin(), rt_refresh_end()) is used for removing stale routes after reestablishment of BGP session during graceful restart.

### Function

int bgp_open (struct bgp_proto * p) -- open a BGP instance

### Arguments

struct bgp_proto * p

  BGP instance

### Description

This function allocates and configures shared BGP resources. Should be called as the last step during initialization (when lock is acquired and neighbor is ready). When error, state changed to PS_DOWN, -1 is returned and caller should return immediately.

### Function

void bgp_close (struct bgp_proto * p, int apply_md5) -- close a BGP instance

### Arguments

struct bgp_proto * p

  BGP instance

int apply_md5

  0 to disable unsetting MD5 auth

### Description

This function frees and deconfigures shared BGP resources. apply_md5 is set to 0 when bgp_close is called as a cleanup from failed bgp_open().

### Function

void bgp_start_timer (timer * t, int value) -- start a BGP timer

### Arguments

timer * t

  timer

int value

  time to fire (0 to disable the timer)

### Description

This functions calls tm_start() on t with time value and the amount of randomization suggested by the BGP standard. Please use it for all BGP timers.

### Function

void bgp_close_conn (struct bgp_conn * conn) -- close a BGP connection

### Arguments

struct bgp_conn * conn

  connection to close

### Description

This function takes a connection described by the bgp_conn structure, closes its socket and frees all resources associated with it.

### Function

void bgp_update_startup_delay (struct bgp_proto * p) -- update a startup delay

### Arguments

struct bgp_proto * p

  BGP instance

### Description

This function updates a startup delay that is used to postpone next BGP connect. It also handles disable_after_error and might stop BGP instance when error happened and disable_after_error is on.

It should be called when BGP protocol error happened.

### Function

void bgp_handle_graceful_restart (struct bgp_proto * p) -- handle detected BGP graceful restart

### Arguments

struct bgp_proto * p

  BGP instance

### Description

This function is called when a BGP graceful restart of the neighbor is detected (when the TCP connection fails or when a new TCP connection appears). The function activates processing of the restart - starts routing table refresh cycle and activates BGP restart timer. The protocol state goes back to PS_START, but changing BGP state back to BS_IDLE is left for the caller.

### Function

void bgp_graceful_restart_done (struct bgp_proto * p) -- finish active BGP graceful restart

### Arguments

struct bgp_proto * p

  BGP instance

### Description

This function is called when the active BGP graceful restart of the neighbor should be finished - either successfully (the neighbor sends all paths and reports end-of-RIB on the new session) or unsuccessfully (the neighbor does not support BGP graceful restart on the new session). The function ends routing table refresh cycle and stops BGP restart timer.

### Function

void bgp_graceful_restart_timeout (timer * t) -- timeout of graceful restart 'restart timer'

### Arguments

timer * t

  timer

### Description

This function is a timeout hook for gr_timer, implementing BGP restart time limit for reestablisment of the BGP session after the graceful restart. When fired, we just proceed with the usual protocol restart.

### Function

void bgp_refresh_begin (struct bgp_proto * p) -- start incoming enhanced route refresh sequence

### Arguments

struct bgp_proto * p

  BGP instance

### Description

This function is called when an incoming enhanced route refresh sequence is started by the neighbor, demarcated by the BoRR packet. The function updates the load state and starts the routing table refresh cycle. Note that graceful restart also uses routing table refresh cycle, but RFC 7313 and load states ensure that these two sequences do not overlap.

### Function

void bgp_refresh_end (struct bgp_proto * p) -- finish incoming enhanced route refresh sequence

### Arguments

struct bgp_proto * p

  BGP instance

### Description

This function is called when an incoming enhanced route refresh sequence is finished by the neighbor, demarcated by the EoRR packet. The function updates the load state and ends the routing table refresh cycle. Routes not received during the sequence are removed by the nest.

### Function

void bgp_connect (struct bgp_proto * p) -- initiate an outgoing connection

### Arguments

struct bgp_proto * p

  BGP instance

### Description

The bgp_connect() function creates a new bgp_conn and initiates a TCP connection to the peer. The rest of connection setup is governed by the BGP state machine as described in the standard.

### Function

struct bgp_proto * bgp_find_proto (sock * sk) -- find existing proto for incoming connection

### Arguments

sock * sk

  TCP socket

### Function

int bgp_incoming_connection (sock * sk, int dummy UNUSED) -- handle an incoming connection

### Arguments

sock * sk

  TCP socket

int dummy UNUSED

  -- undescribed --

### Description

This function serves as a socket hook for accepting of new BGP connections. It searches a BGP instance corresponding to the peer which has connected and if such an instance exists, it creates a bgp_conn structure, attaches it to the instance and either sends an Open message or (if there already is an active connection) it closes the new connection by sending a Notification message.

### Function

void bgp_error (struct bgp_conn * c, unsigned code, unsigned subcode, byte * data, int len) -- report a protocol error

### Arguments

struct bgp_conn * c

  connection

unsigned code

  error code (according to the RFC)

unsigned subcode

  error sub-code

byte * data

  data to be passed in the Notification message

int len

  length of the data

### Description

bgp_error() sends a notification packet to tell the other side that a protocol error has occurred (including the data considered erroneous if possible) and closes the connection.

### Function

void bgp_store_error (struct bgp_proto * p, struct bgp_conn * c, u8 class, u32 code) -- store last error for status report

### Arguments

struct bgp_proto * p

  BGP instance

struct bgp_conn * c

  connection

u8 class

  error class (BE_xxx constants)

u32 code

  error code (class specific)

### Description

bgp_store_error() decides whether given error is interesting enough and store that error to last_error variables of p

### Function

int bgp_fire_tx (struct bgp_conn * conn) -- transmit packets

### Arguments

struct bgp_conn * conn

  connection

### Description

Whenever the transmit buffers of the underlying TCP connection are free and we have any packets queued for sending, the socket functions call bgp_fire_tx() which takes care of selecting the highest priority packet queued (Notification > Keepalive > Open > Update), assembling its header and body and sending it to the connection.

### Function

void bgp_schedule_packet (struct bgp_conn * conn, int type) -- schedule a packet for transmission

### Arguments

struct bgp_conn * conn

  connection

int type

  packet type

### Description

Schedule a packet of type type to be sent as soon as possible.

### Function

const char * bgp_error_dsc (unsigned code, unsigned subcode) -- return BGP error description

### Arguments

unsigned code

  BGP error code

unsigned subcode

  BGP error subcode

### Description

bgp_error_dsc() returns error description for BGP errors which might be static string or given temporary buffer.

### Function

void bgp_rx_packet (struct bgp_conn * conn, byte * pkt, unsigned len) -- handle a received packet

### Arguments

struct bgp_conn * conn

  BGP connection

byte * pkt

  start of the packet

unsigned len

  packet size

### Description

bgp_rx_packet() takes a newly received packet and calls the corresponding packet handler according to the packet type.

### Function

int bgp_rx (sock * sk, int size) -- handle received data

### Arguments

sock * sk

  socket

int size

  amount of data received

### Description

bgp_rx() is called by the socket layer whenever new data arrive from the underlying TCP connection. It assembles the data fragments to packets, checks their headers and framing and passes complete packets to bgp_rx_packet().

### Function

unsigned int bgp_encode_attrs (struct bgp_proto * p, byte * w, ea_list * attrs, int remains) -- encode BGP attributes

### Arguments

struct bgp_proto * p

  BGP instance

byte * w

  buffer

ea_list * attrs

  a list of extended attributes

int remains

  remaining space in the buffer

### Description

The bgp_encode_attrs() function takes a list of extended attributes and converts it to its BGP representation (a part of an Update message).

### Result

Length of the attribute block generated or -1 if not enough space.

### Function

struct rta * bgp_decode_attrs (struct bgp_conn * conn, byte * attr, unsigned int len, struct linpool * pool, int mandatory) -- check and decode BGP attributes

### Arguments

struct bgp_conn * conn

  connection

byte * attr

  start of attribute block

unsigned int len

  length of attribute block

struct linpool * pool

  linear pool to make all the allocations in

int mandatory

  1 iff presence of mandatory attributes has to be checked

### Description

This function takes a BGP attribute block (a part of an Update message), checks its consistency and converts it to a list of BIRD route attributes represented by a rta.

## 5.3 Open Shortest Path First (OSPF)

The OSPF protocol is quite complicated and its complex implemenation is split to many files. In `ospf.c`, you will find mainly the interface for communication with the core (e.g., reconfiguration hooks, shutdown and initialisation and so on). File `iface.c` contains the interface state machine and functions for allocation and deallocation of OSPF's interface data structures. Source `neighbor.c` includes the neighbor state machine and functions for election of Designated Router and Backup Designated router. In `packet.c`, you will find various functions for sending and receiving generic OSPF packets. There are also routines for authentication and checksumming. In `hello.c`, there are routines for sending and receiving of hello packets as well as functions for maintaining wait times and the inactivity timer. Files `lsreq.c`, `lsack.c`, `dbdes.c` contain functions for sending and receiving of link-state requests, link-state acknowledgements and database descriptions respectively. In `lsupd.c`, there are functions for sending and receiving of link-state updates and also the flooding algorithm. Source `topology.c` is a place where routines for searching LSAs in the link-state database, adding and deleting them reside, there also are functions for originating of various types of LSAs (router LSA, net LSA, external LSA). File `rt.c` contains routines for calculating the routing table. `lsalib.c` is a set of various functions for working with the LSAs (endianity conversions, calculation of checksum etc.).

One instance of the protocol is able to hold LSA databases for multiple OSPF areas, to exchange routing information between multiple neighbors and to calculate the routing tables. The core structure is ospf_proto to which multiple ospf_area and ospf_iface structures are connected. ospf_proto is also connected to top_hash_graph which is a dynamic hashing structure that describes the link-state database. It allows fast search, addition and deletion. Each LSA is kept in two pieces: header and body. Both of them are kept in the endianity of the CPU.

In OSPFv2 specification, it is implied that there is one IP prefix for each physical network/interface (unless it is an ptp link). But in modern systems, there might be more independent IP prefixes associated with an interface. To handle this situation, we have one ospf_iface for each active IP prefix (instead for each active iface); This behaves like virtual interface for the purpose of OSPF. If we receive packet, we associate it with a proper virtual interface mainly according to its source address.

OSPF keeps one socket per ospf_iface. This allows us (compared to one socket approach) to evade problems with a limit of multicast groups per socket and with sending multicast packets to appropriate interface in a portable way. The socket is associated with underlying physical iface and should not receive packets received on other ifaces (unfortunately, this is not true on BSD). Generally, one packet can be received by more sockets (for example, if there are more ospf_iface on one physical iface), therefore we explicitly filter received packets according to src/dst IP address and received iface.

Vlinks are implemented using particularly degenerate form of ospf_iface, which has several exceptions: it does not have its iface or socket (it copies these from 'parent' ospf_iface) and it is present in iface list even when down (it is not freed in ospf_iface_down()).

The heart beat of ospf is ospf_disp(). It is called at regular intervals (ospf_proto->tick). It is responsible for aging and flushing of LSAs in the database, updating topology information in LSAs and for routing table calculation.

To every ospf_iface, we connect one or more ospf_neighbor's -- a structure containing many timers and queues for building adjacency and for exchange of routing messages.

BIRD's OSPF implementation respects RFC2328 in every detail, but some of internal algorithms do differ. The RFC recommends making a snapshot of the link-state database when a new adjacency is forming and sending the database description packets based on the information in this snapshot. The database can be quite large in some networks, so rather we walk through a slist structure which allows us to continue even if the actual LSA we were working with is deleted. New LSAs are added at the tail of this slist.

We also do not keep a separate OSPF routing table, because the core helps us by being able to recognize when a route is updated to an identical one and it suppresses the update automatically. Due to this, we can flush all the routes we have recalculated and also those we have deleted to the core's routing table and the core will take care of the rest. This simplifies the process and conserves memory.

Supported standards: - RFC 2328 - main OSPFv2 standard - RFC 5340 - main OSPFv3 standard - RFC 3101 - OSPFv2 NSSA areas - RFC 6549 - OSPFv2 multi-instance extensions - RFC 6987 - OSPF stub router advertisement

### Function

void ospf_disp (timer * timer) -- invokes routing table calculation, aging and also area_disp()

### Arguments

timer * timer

  timer usually called every ospf_proto->tick second, timer->data point to ospf_proto

### Function

int ospf_import_control (struct proto * P, rte ** new, ea_list ** attrs, struct linpool * pool) -- accept or reject new route from nest's routing table

### Arguments

struct proto * P

  OSPF protocol instance

rte ** new

  the new route

ea_list ** attrs

  list of attributes

struct linpool * pool

  pool for allocation of attributes

### Description

Its quite simple. It does not accept our own routes and leaves the decision on import to the filters.

### Function

int ospf_shutdown (struct proto * P) -- Finish of OSPF instance

### Arguments

struct proto * P

  OSPF protocol instance

### Description

RFC does not define any action that should be taken before router shutdown. To make my neighbors react as fast as possible, I send them hello packet with empty neighbor list. They should start their neighbor state machine with event NEIGHBOR_1WAY.

### Function

int ospf_reconfigure (struct proto * P, struct proto_config * c) -- reconfiguration hook

### Arguments

struct proto * P

  current instance of protocol (with old configuration)

struct proto_config * c

  new configuration requested by user

### Description

This hook tries to be a little bit intelligent. Instance of OSPF will survive change of many constants like hello interval, password change, addition or deletion of some neighbor on nonbroadcast network, cost of interface, etc.

### Function

struct top_hash_entry * ospf_install_lsa (struct ospf_proto * p, struct ospf_lsa_header * lsa, u32 type, u32 domain, void * body) -- install new LSA into database

### Arguments

struct ospf_proto * p

  OSPF protocol instance

struct ospf_lsa_header * lsa

  LSA header

u32 type

  type of LSA

u32 domain

  domain of LSA

void * body

  pointer to LSA body

### Description

This function ensures installing new LSA received in LS update into LSA database. Old instance is replaced. Several actions are taken to detect if new routing table calculation is necessary. This is described in 13.2 of RFC 2328. This function is for received LSA only, locally originated LSAs are installed by ospf_originate_lsa().

The LSA body in body is expected to be mb_allocated by the caller and its ownership is transferred to the LSA entry structure.

### Function

void ospf_advance_lsa (struct ospf_proto * p, struct top_hash_entry * en, struct ospf_lsa_header * lsa, u32 type, u32 domain, void * body) -- handle received unexpected self-originated LSA

### Arguments

struct ospf_proto * p

  OSPF protocol instance

struct top_hash_entry * en

  current LSA entry or NULL

struct ospf_lsa_header * lsa

  new LSA header

u32 type

  type of LSA

u32 domain

  domain of LSA

void * body

  pointer to LSA body

### Description

This function handles received unexpected self-originated LSA (lsa, body) by either advancing sequence number of the local LSA instance (en) and propagating it, or installing the received LSA and immediately flushing it (if there is no local LSA; i.e., en is NULL or MaxAge).

The LSA body in body is expected to be mb_allocated by the caller and its ownership is transferred to the LSA entry structure or it is freed.

### Function

struct top_hash_entry * ospf_originate_lsa (struct ospf_proto * p, struct ospf_new_lsa * lsa) -- originate new LSA

### Arguments

struct ospf_proto * p

  OSPF protocol instance

struct ospf_new_lsa * lsa

  New LSA specification

### Description

This function prepares a new LSA, installs it into the LSA database and floods it. If the new LSA cannot be originated now (because the old instance was originated within MinLSInterval, or because the LSA seqnum is currently wrapping), the origination is instead scheduled for later. If the new LSA is equivalent to the current LSA, the origination is skipped. In all cases, the corresponding LSA entry is returned. The new LSA is based on the LSA specification (lsa) and the LSA body from lsab buffer of p, which is emptied after the call. The opposite of this function is ospf_flush_lsa().

### Function

void ospf_flush_lsa (struct ospf_proto * p, struct top_hash_entry * en) -- flush LSA from OSPF domain

### Arguments

struct ospf_proto * p

  OSPF protocol instance

struct top_hash_entry * en

  LSA entry to flush

### Description

This function flushes en from the OSPF domain by setting its age to LSA_MAXAGE and flooding it. That also triggers subsequent events in LSA lifecycle leading to removal of the LSA from the LSA database (e.g. the LSA content is freed when flushing is acknowledged by neighbors). The function does nothing if the LSA is already being flushed. LSA entries are not immediately removed when being flushed, the caller may assume that en still exists after the call. The function is the opposite of ospf_originate_lsa() and is supposed to do the right thing even in cases of postponed origination.

### Function

void ospf_update_lsadb (struct ospf_proto * p) -- update LSA database

### Arguments

struct ospf_proto * p

  OSPF protocol instance

### Description

This function is periodicaly invoked from ospf_disp(). It does some periodic or postponed processing related to LSA entries. It originates postponed LSAs scheduled by ospf_originate_lsa(), It continues in flushing processes started by ospf_flush_lsa(). It also periodically refreshs locally originated LSAs -- when the current instance is older LSREFRESHTIME, a new instance is originated. Finally, it also ages stored LSAs and flushes ones that reached LSA_MAXAGE.

The RFC 2328 says that a router should periodically check checksums of all stored LSAs to detect hardware problems. This is not implemented.

### Function

void ospf_originate_ext_lsa (struct ospf_proto * p, struct ospf_area * oa, ort * nf, u8 mode, u32 metric, u32 ebit, ip_addr fwaddr, u32 tag, int pbit) -- new route received from nest and filters

### Arguments

struct ospf_proto * p

  OSPF protocol instance

struct ospf_area * oa

  ospf_area for which LSA is originated

ort * nf

  network prefix and mask

u8 mode

  the mode of the LSA (LSA_M_EXPORT or LSA_M_RTCALC)

u32 metric

  the metric of a route

u32 ebit

  E-bit for route metric (bool)

ip_addr fwaddr

  the forwarding address

u32 tag

  the route tag

int pbit

  P-bit for NSSA LSAs (bool), ignored for external LSAs

### Description

If I receive a message that new route is installed, I try to originate an external LSA. If oa is an NSSA area, NSSA-LSA is originated instead. oa should not be a stub area. src does not specify whether the LSA is external or NSSA, but it specifies the source of origination - the export from ospf_rt_notify(), or the NSSA-EXT translation.

### Function

struct top_graph * ospf_top_new (struct ospf_proto * p, pool * pool) -- allocated new topology database

### Arguments

struct ospf_proto * p

  OSPF protocol instance

pool * pool

  pool for allocation

### Description

This dynamically hashed structure is used for keeping LSAs. Mainly it is used for the LSA database of the OSPF protocol, but also for LSA retransmission and request lists of OSPF neighbors.

### Function

void ospf_neigh_chstate (struct ospf_neighbor * n, u8 state) -- handles changes related to new or lod state of neighbor

### Arguments

struct ospf_neighbor * n

  OSPF neighbor

u8 state

  new state

### Description

Many actions have to be taken acording to a change of state of a neighbor. It starts rxmt timers, call interface state machine etc.

### Function

void ospf_neigh_sm (struct ospf_neighbor * n, int event) -- ospf neighbor state machine

### Arguments

struct ospf_neighbor * n

  neighor

int event

  actual event

### Description

This part implements the neighbor state machine as described in 10.3 of RFC 2328. The only difference is that state NEIGHBOR_ATTEMPT is not used. We discover neighbors on nonbroadcast networks in the same way as on broadcast networks. The only difference is in sending hello packets. These are sent to IPs listed in ospf_iface->nbma_list .

### Function

void ospf_dr_election (struct ospf_iface * ifa) -- (Backup) Designed Router election

### Arguments

struct ospf_iface * ifa

  actual interface

### Description

When the wait timer fires, it is time to elect (Backup) Designated Router. Structure describing me is added to this list so every electing router has the same list. Backup Designated Router is elected before Designated Router. This process is described in 9.4 of RFC 2328. The function is supposed to be called only from ospf_iface_sm() as a part of the interface state machine.

### Function

void ospf_iface_chstate (struct ospf_iface * ifa, u8 state) -- handle changes of interface state

### Arguments

struct ospf_iface * ifa

  OSPF interface

u8 state

  new state

### Description

Many actions must be taken according to interface state changes. New network LSAs must be originated, flushed, new multicast sockets to listen for messages for ALLDROUTERS have to be opened, etc.

### Function

void ospf_iface_sm (struct ospf_iface * ifa, int event) -- OSPF interface state machine

### Arguments

struct ospf_iface * ifa

  OSPF interface

int event

  event comming to state machine

### Description

This fully respects 9.3 of RFC 2328 except we have slightly different handling of DOWN and LOOP state. We remove intefaces that are DOWN. DOWN state is used when an interface is waiting for a lock. LOOP state is used when an interface does not have a link.

### Function

int ospf_rx_hook (sock * sk, int len)

### Arguments

sock * sk

  socket we received the packet.

int len

  -- undescribed --

### Description

This is the entry point for messages from neighbors. Many checks (like authentication, checksums, size) are done before the packet is passed to non generic functions.

### Function

int lsa_validate (struct ospf_lsa_header * lsa, u32 lsa_type, int ospf2, void * body) -- check whether given LSA is valid

### Arguments

struct ospf_lsa_header * lsa

  LSA header

u32 lsa_type

  -- undescribed --

int ospf2

  -- undescribed --

void * body

  pointer to LSA body

### Description

Checks internal structure of given LSA body (minimal length, consistency). Returns true if valid.

### Function

void ospf_send_dbdes (struct ospf_proto * p, struct ospf_neighbor * n) -- transmit database description packet

### Arguments

struct ospf_proto * p

  -- undescribed --

struct ospf_neighbor * n

  neighbor

### Description

Sending of a database description packet is described in 10.8 of RFC 2328. Reception of each packet is acknowledged in the sequence number of another. When I send a packet to a neighbor I keep a copy in a buffer. If the neighbor does not reply, I don't create a new packet but just send the content of the buffer.

### Function

void ospf_rt_spf (struct ospf_proto * p) -- calculate internal routes

### Arguments

struct ospf_proto * p

  OSPF protocol instance

### Description

Calculation of internal paths in an area is described in 16.1 of RFC 2328. It's based on Dijkstra's shortest path tree algorithms. This function is invoked from ospf_disp().

## 5.4 Pipe

The Pipe protocol is very simple. It just connects to two routing tables using proto_add_announce_hook() and whenever it receives a rt_notify() about a change in one of the tables, it converts it to a rte_update() in the other one.

To avoid pipe loops, Pipe keeps a `being updated' flag in each routing table.

A pipe has two announce hooks, the first connected to the main table, the second connected to the peer table. When a new route is announced on the main table, it gets checked by an export filter in ahook 1, and, after that, it is announced to the peer table via rte_update(), an import filter in ahook 2 is called. When a new route is announced in the peer table, an export filter in ahook2 and an import filter in ahook 1 are used. Oviously, there is no need in filtering the same route twice, so both import filters are set to accept, while user configured 'import' and 'export' filters are used as export filters in ahooks 2 and 1. Route limits are handled similarly, but on the import side of ahooks.

## 5.5 Routing Information Protocol

RIP is a pretty simple protocol, so about a half of its code is interface with the core.

We maintain our own linked list of rip_entry structures -- it serves as our small routing table. RIP never adds to this linked list upon packet reception; instead, it lets the core know about data from the packet and waits for the core to call rip_rt_notify().

Within rip_tx(), the list is walked and a packet is generated using rip_tx_prepare(). This gets tricky because we may need to send more than one packet to one destination. Struct rip_connection is used to hold context information such as how many of rip_entry's we have already sent and it's also used to protect against two concurrent sends to one destination. Each rip_interface has at most one rip_connection.

We are not going to honor requests for sending part of routing table. That would need to turn split horizon off etc.

About triggered updates, RFC says: when a triggered update was sent, don't send a new one for something between 1 and 5 seconds (and send one after that). We do something else: each 5 seconds, we look for any changed routes and broadcast them.

### Function

void rip_timer (timer * t)

### Arguments

timer * t

  timer

### Description

Broadcast routing tables periodically (using rip_tx) and kill routes that are too old. RIP keeps a list of its own entries present in the core table by a linked list (functions rip_rte_insert() and rip_rte_delete() are responsible for that), it walks this list in the timer and in case an entry is too old, it is discarded.

### Function

struct rip_interface * new_iface (struct proto * p, struct iface * new, unsigned long flags, struct iface_patt * patt)

### Arguments

struct proto * p

  myself

struct iface * new

  interface to be created or NULL if we are creating a magic socket. The magic socket is used for listening and also for sending requested responses.

unsigned long flags

  interface flags

struct iface_patt * patt

  pattern this interface matched, used for access to config options

### Description

Create an interface structure and start listening on the interface.

## 5.6 Router Advertisements

The RAdv protocol is implemented in two files: `radv.c` containing the interface with BIRD core and the protocol logic and `packets.c` handling low level protocol stuff (RX, TX and packet formats). The protocol does not export any routes.

The RAdv is structured in the usual way - for each handled interface there is a structure radv_iface that contains a state related to that interface together with its resources (a socket, a timer). There is also a prepared RA stored in a TX buffer of the socket associated with an iface. These iface structures are created and removed according to iface events from BIRD core handled by radv_if_notify() callback.

The main logic of RAdv consists of two functions: radv_iface_notify(), which processes asynchronous events (specified by RA_EV_* codes), and radv_timer(), which triggers sending RAs and computes the next timeout.

The RAdv protocol could receive routes (through radv_import_control() and radv_rt_notify()), but only the configured trigger route is tracked (in active var). When a radv protocol is reconfigured, the connected routing table is examined (in radv_check_active()) to have proper active value in case of the specified trigger prefix was changed.

Supported standards: - RFC 4861 - main RA standard - RFC 6106 - DNS extensions (RDDNS, DNSSL) - RFC 4191 (partial) - Default Router Preference

## 5.7 Static

The Static protocol is implemented in a straightforward way. It keeps two lists of static routes: one containing interface routes and one holding the remaining ones. Interface routes are inserted and removed according to interface events received from the core via the if_notify() hook. Routes pointing to a neighboring router use a sticky node in the neighbor cache to be notified about gaining or losing the neighbor. Special routes like black holes or rejects are inserted all the time.

Multipath routes are tricky. Because these routes depends on several neighbors we need to integrate that to the neighbor notification handling, we use dummy static_route nodes, one for each nexthop. Therefore, a multipath route consists of a master static_route node (of dest RTD_MULTIPATH), which specifies prefix and is used in most circumstances, and a list of dummy static_route nodes (of dest RTD_NONE), which stores info about nexthops and are connected to neighbor entries and neighbor notifications. Dummy nodes are chained using mp_next, they aren't in other_routes list, and abuse some fields (masklen, if_name) for other purposes.

The only other thing worth mentioning is that when asked for reconfiguration, Static not only compares the two configurations, but it also calculates difference between the lists of static routes and it just inserts the newly added routes and removes the obsolete ones.

## 5.8 Direct

The Direct protocol works by converting all ifa_notify() events it receives to rte_update() calls for the corresponding network.

Next Previous Contents