Fixes to the progdoc.
This commit is contained in:
parent
38203d789a
commit
58f7d004fd
17 changed files with 73 additions and 74 deletions
|
@ -10,12 +10,12 @@
|
|||
* DOC: Lexical analyzer
|
||||
*
|
||||
* The lexical analyzer used for configuration files and CLI commands
|
||||
* is generated using the |flex| tool accompanied with a couple of
|
||||
* is generated using the |flex| tool accompanied by a couple of
|
||||
* functions maintaining the hash tables containing information about
|
||||
* symbols and keywords.
|
||||
*
|
||||
* Each symbol is represented by a &symbol structure containing name
|
||||
* of the symbol, its scope, symbol class (%SYM_PROTO for a name of a protocol,
|
||||
* of the symbol, its lexical scope, symbol class (%SYM_PROTO for a name of a protocol,
|
||||
* %SYM_NUMBER for a numeric constant etc.) and class dependent data.
|
||||
* When an unknown symbol is encountered, it's automatically added to the
|
||||
* symbol table with class %SYM_VOID.
|
||||
|
@ -454,7 +454,7 @@ cf_symbol_class_name(struct symbol *sym)
|
|||
* the |gen_parser.m4| script.
|
||||
*
|
||||
* Grammar snippets are files (usually with extension |.Y|) contributed
|
||||
* by various BIRD modules to provide information about syntax of their
|
||||
* by various BIRD modules in order to provide information about syntax of their
|
||||
* configuration and their CLI commands. Each snipped consists of several
|
||||
* section, each of them starting with a special keyword: |CF_HDR| for
|
||||
* a list of |#include| directives needed by the C code, |CF_DEFINES|
|
||||
|
|
|
@ -9,9 +9,9 @@
|
|||
/**
|
||||
* DOC: Configuration manager
|
||||
*
|
||||
* Configuration of BIRD is complex, but straightforward. There exist three
|
||||
* Configuration of BIRD is complex, yet straightforward. There exist three
|
||||
* modules taking care of the configuration: config manager (which takes care
|
||||
* of storage of config information and controls switching between configs),
|
||||
* of storage of the config information and controls switching between configs),
|
||||
* lexical analyzer and parser.
|
||||
*
|
||||
* The configuration manager stores each config as a &config structure
|
||||
|
@ -27,7 +27,7 @@
|
|||
*
|
||||
* Loading of new configuration is very simple: just call config_alloc()
|
||||
* to get a new &config structure, then use config_parse() to parse a
|
||||
* configuration file and fill all information in the structure
|
||||
* configuration file and fill all fields of the structure
|
||||
* and finally ask the config manager to switch to the new
|
||||
* config by calling config_commit().
|
||||
*
|
||||
|
|
|
@ -2,12 +2,12 @@
|
|||
|
||||
<sect>Introduction
|
||||
|
||||
<p>This document describes the internal workings of the BIRD, its architecture,
|
||||
<p>This document describes the internal workings of BIRD, its architecture,
|
||||
design decisions and rationale behind them. It also contains documentation on
|
||||
all the essential components of the system and their interfaces.
|
||||
|
||||
<p>Routing daemons are very complicated things which need to act in real time
|
||||
to complex sequences external events, react correctly even to the most erroneous behavior
|
||||
to complex sequences of external events, respond correctly even to the most erroneous behavior
|
||||
of their environment and still handle enormous amount of data with reasonable
|
||||
speed. Due to all of this, their design is very tricky as one needs to carefully
|
||||
balance between efficiency, stability and (last, but not least) simplicity of
|
||||
|
@ -21,7 +21,7 @@ by the program source itself together with comments contained therein.
|
|||
|
||||
<p>When planning the architecture of BIRD, we've taken a close look at the other existing routing
|
||||
daemons and also at some of the operating systems used on dedicated routers, gathered all important
|
||||
features and added lots of new ones to overcome their shortcomings and better match the requirements
|
||||
features and added lots of new ones to overcome their shortcomings and to better match the requirements
|
||||
of routing in today's Internet: IPv6, policy routing, route filtering and so on. From this
|
||||
planning, the following set of design goals has arisen:
|
||||
|
||||
|
@ -36,8 +36,8 @@ This leads to abstraction of IP addresses and operations on them.
|
|||
<item><it>Minimize OS dependent code to make porting as easy as possible.</it>
|
||||
Unfortunately, such code cannot be avoided at all as the details of communication with
|
||||
the IP stack differ from OS to OS and they often vary even between different
|
||||
versions of the same OS, but we can isolate such code in special modules and
|
||||
do the porting by changing just these modules.
|
||||
versions of the same OS. But we can isolate such code in special modules and
|
||||
do the porting by changing or replacing just these modules.
|
||||
Also, don't rely on specific features of various operating systems, but be able
|
||||
to make use of them if they are available.
|
||||
|
||||
|
@ -62,7 +62,7 @@ to read the new configuration and smoothly adapt to it without disturbing parts
|
|||
the routing process which are not affected by the change.
|
||||
|
||||
<item><it>Be able to be controlled online.</it>
|
||||
In addition to online reconfiguration, a routing daemon should be able to communicate
|
||||
In addition to the online reconfiguration, a routing daemon should be able to communicate
|
||||
with the user and with many other programs (primarily scripts used for network maintenance)
|
||||
in order to make it possible to inspect contents of routing tables, status of all
|
||||
routing protocols and also to control their behavior (i.e., it should be possible
|
||||
|
@ -71,7 +71,7 @@ this, we implement a simple command-line protocol based on those used by FTP and
|
|||
(that is textual commands and textual replies accompanied by a numeric code which makes
|
||||
them both readable to a human and easy to recognize in software).
|
||||
|
||||
<item><it>Respond to all protocol events in real time.</it>
|
||||
<item><it>Respond to all events in real time.</it>
|
||||
A typical solution to this problem is to use lots of threads to separate the workings
|
||||
of all the routing protocols and also of the user interface parts and to hope that
|
||||
the scheduler will assign time to them in a fair enough manner. This is surely a good
|
||||
|
@ -88,18 +88,18 @@ the following types of modules:
|
|||
|
||||
<descrip>
|
||||
|
||||
<tagp>Core modules</tagp> implement the core functions of BIRD as taking care
|
||||
<tagp>Core modules</tagp> implement the core functions of BIRD: taking care
|
||||
of routing tables, keeping protocol status, interacting with the user using
|
||||
the Command-Line Interface (to be called CLI in the rest of this document)
|
||||
etc.
|
||||
|
||||
<tagp>Library modules</tagp> form a large set of various library functions
|
||||
implementing several data abstractions, utility functions and also functions
|
||||
which are a part of standard libraries on some systems, but missing on other
|
||||
which are a part of the standard libraries on some systems, but missing on other
|
||||
ones.
|
||||
|
||||
<tagp>Resource management modules</tagp> take care of resources, their allocation
|
||||
and automatic freeing when the module having requested them ceases to exist.
|
||||
and automatic freeing when the module having requested shuts itself down.
|
||||
|
||||
<tagp>Configuration modules</tagp> are fragments of lexical analyzer,
|
||||
grammar rules and the corresponding snippets of C code. For each group
|
||||
|
@ -120,7 +120,7 @@ interface to the CLI.
|
|||
|
||||
<sect>Implementation
|
||||
|
||||
<p>BIRD has been written in GNU C. We've considered using of C++, but we've
|
||||
<p>BIRD has been written in GNU C. We've considered using C++, but we've
|
||||
preferred the simplicity and straightforward nature of C which gives us fine
|
||||
control over all implementation details and on the other hand enough
|
||||
instruments to build the abstractions we need.
|
||||
|
|
|
@ -13,12 +13,10 @@
|
|||
* Since BIRD is single-threaded, it requires long lasting tasks to be split to smaller
|
||||
* parts, so that no module can monopolize the CPU. To split such a task, just create
|
||||
* an &event resource, point it to the function you want to have called and call ev_schedule()
|
||||
* to ask the core to run the event when nothing more important will require attention.
|
||||
* to ask the core to run the event when nothing more important requires attention.
|
||||
*
|
||||
* You can also define your own event lists (the &event_list structure), enqueue your
|
||||
* events in them and explicitly ask to run them.
|
||||
*
|
||||
* The actual implementation is system dependent.
|
||||
*/
|
||||
|
||||
#include "nest/bird.h"
|
||||
|
|
|
@ -21,7 +21,7 @@ modules of BIRD, deallocates everything automatically when a module
|
|||
shuts down and it's is able to print out the list of resources and
|
||||
the corresponding modules they are allocated by.
|
||||
|
||||
<p>Each allocated resource (and from now we'll speak about allocated
|
||||
<p>Each allocated resource (from now we'll speak about allocated
|
||||
resources only) is represented by a structure starting with a standard
|
||||
header (struct <struct/resource/) consisting of a list node (resources are
|
||||
often linked to various lists) and a pointer to <struct/resclass/ -- a resource
|
||||
|
|
|
@ -19,10 +19,10 @@
|
|||
* constructors and destructors.
|
||||
*
|
||||
* When the |DEBUGGING| switch is turned on, we automatically fill all
|
||||
* newly allocated and freed blocks with a special patterns to make detection
|
||||
* newly allocated and freed blocks with a special pattern to make detection
|
||||
* of use of uninitialized or already freed memory easier.
|
||||
*
|
||||
* Example: Nodes of a FIB are allocated from a Slab.
|
||||
* Example: Nodes of a FIB are allocated from a per-FIB Slab.
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
|
|
|
@ -26,12 +26,12 @@
|
|||
* a continuation line, the whole prefix can be replaced by a single
|
||||
* white space character.
|
||||
*
|
||||
* Reply codes starting with 0 describe `action successfully completed' messages,
|
||||
* 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 closes, not depending
|
||||
* 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
|
||||
|
@ -40,9 +40,9 @@
|
|||
* 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 or (in case it expects the reply will be long)
|
||||
* the whole reply and returns 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 will be transferred to the user.
|
||||
* 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
|
||||
|
|
|
@ -15,14 +15,14 @@
|
|||
* 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 being shut down and a new one
|
||||
* 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 doesn't
|
||||
* 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 which is in turn a kind of
|
||||
* 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 and interface.
|
||||
|
|
|
@ -20,17 +20,17 @@
|
|||
* 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 data belonging to a
|
||||
* address is set to %SCOPE_HOST) together with per-neighbor data belonging to a
|
||||
* single protocol.
|
||||
*
|
||||
* Active entries represent known neighbors and are stored in a hash
|
||||
* table (to allow fast retrieval based on IP address of the node) and
|
||||
* table (to allow fast retrieval based on the IP address of the node) and
|
||||
* two linked lists: one global and one per-interface (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 enqueued in a special list which is walked
|
||||
* whenever an interface becomes up.
|
||||
* whenever an interface changes its state to up.
|
||||
*
|
||||
* When a neighbor event occurs (a neighbor gets disconnected or a sticky
|
||||
* inactive neighbor becomes connected), the protocol hook neigh_notify()
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
/**
|
||||
* DOC: Protocol hooks
|
||||
*
|
||||
* Each protocol provides a rich set of hook functions referred to by pointers
|
||||
* 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
|
||||
|
|
|
@ -67,7 +67,7 @@ the following states:
|
|||
<p>Unless the protocol is in the <tt/PS_DOWN/ state, it can decide to change
|
||||
its state by calling the <func/proto_notify_state/ function.
|
||||
|
||||
<p>At any time, the core code can ask the protocol to shut down by calling its stop() hook.
|
||||
<p>At any time, the core code can ask the protocol to shut itself down by calling its stop() hook.
|
||||
|
||||
<p>The <em/core state machine/ takes care of the core view of protocol state.
|
||||
The states are traversed according to changes of the protocol state machine, but
|
||||
|
|
|
@ -21,7 +21,7 @@
|
|||
* 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 buckets are sorted according to the primary hash
|
||||
* 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.
|
||||
*
|
||||
|
@ -400,7 +400,7 @@ fit_put(struct fib_iterator *i, struct fib_node *n)
|
|||
* @f: FIB to be checked
|
||||
*
|
||||
* This debugging function audits a FIB by checking its internal consistency.
|
||||
* Use when you suspect somebody from corrupting innocent data structures.
|
||||
* Use when you suspect somebody of corrupting innocent data structures.
|
||||
*/
|
||||
void
|
||||
fib_check(struct fib *f)
|
||||
|
|
|
@ -16,7 +16,7 @@
|
|||
* There exist 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)
|
||||
* destination networks. For each network (represented by structure &net),
|
||||
* there is a one-way linked list of network entries (&rte), the first entry
|
||||
* on the list being the best possible one (i.e., the one we currently use
|
||||
* for routing), the order of the other ones is undetermined.
|
||||
|
|
|
@ -21,7 +21,7 @@
|
|||
* many connections, but not too much and, which is more important, it makes
|
||||
* BGP much easier to implement.
|
||||
*
|
||||
* Each instance of BGP (corresponding to one BGP peer) is described by a &bgp_proto
|
||||
* 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
|
||||
|
@ -39,7 +39,7 @@
|
|||
* 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
|
||||
* 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
|
||||
|
|
|
@ -18,29 +18,30 @@
|
|||
*/
|
||||
|
||||
/**
|
||||
* DOC: Routing information protocol
|
||||
* DOC: Routing Information Protocol
|
||||
*
|
||||
* Rip is pretty simple protocol so half of this code is interface
|
||||
* with core. We maintain our own linked list of &rip_entry -- it serves
|
||||
* as our small routing table. Rip never adds into this linked list at
|
||||
* packet reception; instead, it lets core know about data from packet,
|
||||
* and waits for core to call our rip_rte_notify.
|
||||
* RIP is a pretty simple protocol, so about a half of its code is interface
|
||||
* with the core.
|
||||
*
|
||||
* Within rip_tx(), this list is
|
||||
* walked, and packet is generated using rip_tx_prepare(). This gets
|
||||
* 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_rte_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 info such as how
|
||||
* many of &rip_entry's we already send, and is also used to protect
|
||||
* from two concurrent sends to one destination. Each &rip_interface has
|
||||
* 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.
|
||||
* routing table. That would need to turn split horizon off etc.
|
||||
*
|
||||
* Triggered updates. RFC says: when triggered update was sent, don't send
|
||||
* new one for something between 1 and 5 seconds (and send one
|
||||
* after that). We do something else: once in 5 second
|
||||
* 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.
|
||||
*/
|
||||
|
||||
|
@ -70,7 +71,7 @@ static struct rip_interface *new_iface(struct proto *p, struct iface *new, unsig
|
|||
#define P_NAME p->name
|
||||
|
||||
/*
|
||||
* DOC: Output processing
|
||||
* Output processing
|
||||
*
|
||||
* This part is responsible for getting packets out to the network.
|
||||
*/
|
||||
|
@ -251,7 +252,7 @@ find_interface(struct proto *p, struct iface *what)
|
|||
}
|
||||
|
||||
/*
|
||||
* DOC: Input processing
|
||||
* Input processing
|
||||
*
|
||||
* This part is responsible for any updates that come from network
|
||||
*/
|
||||
|
@ -466,7 +467,7 @@ rip_rx(sock *s, int size)
|
|||
}
|
||||
|
||||
/*
|
||||
* DOC: Interface to bird core
|
||||
* Interface to BIRD core
|
||||
*/
|
||||
|
||||
static void
|
||||
|
@ -482,10 +483,10 @@ rip_dump_entry( struct rip_entry *e )
|
|||
* @t: timer
|
||||
*
|
||||
* Broadcast routing tables periodically (using rip_tx) and kill
|
||||
* routes that are too old. Rip keeps its own entries in main routing
|
||||
* table linked by link list (functions rip_rte_insert() and
|
||||
* rip_rte_delete() are responsible for that), walks this list in timer
|
||||
* and in case entry is too old, it is discarded.
|
||||
* 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.
|
||||
*/
|
||||
|
||||
static void
|
||||
|
@ -636,13 +637,13 @@ kill_iface(struct proto *p, struct rip_interface *i)
|
|||
/**
|
||||
* new_iface
|
||||
* @p: myself
|
||||
* @new: interface to be created or %NULL if we are creating magic
|
||||
* socket. Magic socket is used for listening, and is also used for
|
||||
* sending requested responses.
|
||||
* @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.
|
||||
* @flags: interface flags
|
||||
* @patt: pattern this interface matched, used for access to config options
|
||||
*
|
||||
* actually create struct interface and start listening to it
|
||||
* Create an interface structure and start listening on the interface.
|
||||
*/
|
||||
static struct rip_interface *
|
||||
new_iface(struct proto *p, struct iface *new, unsigned long flags, struct iface_patt *patt )
|
||||
|
|
|
@ -78,11 +78,11 @@ tracked_fopen(pool *p, char *name, char *mode)
|
|||
*
|
||||
* Timers are resources which represent a wish of a module to call
|
||||
* a function at the specified time. The platform dependent code
|
||||
* doesn't guarantee the exact timing, only that a timer function
|
||||
* doesn't guarantee exact timing, only that a timer function
|
||||
* won't be called before the requested time.
|
||||
*
|
||||
* In BIRD, real time is represented by values of the &bird_clock_t type
|
||||
* which are integral numbers corresponding to a number of seconds since
|
||||
* which are integral numbers interpreted as a number of seconds since
|
||||
* a fixed (but platform dependent) epoch. The current time can be read
|
||||
* from a variable @now with reasonable accuracy.
|
||||
*
|
||||
|
|
|
@ -26,14 +26,14 @@
|
|||
* separate KRT protocols which cooperate with each other [Linux 2.2].
|
||||
* In this case, we keep only a single scan timer.
|
||||
*
|
||||
* We use FIB node flags to keep track of route synchronization status. We also
|
||||
* attach temporary &rte's to the routing tables, but it cannot harm the rest of
|
||||
* BIRD since table synchronization is an atomic process.
|
||||
* We use FIB node flags in the routing table to keep track of route
|
||||
* synchronization status. We also attach temporary &rte's to the routing table,
|
||||
* but it cannot do any harm to the rest of BIRD since table synchronization is
|
||||
* an atomic process.
|
||||
*
|
||||
* When starting up, we cheat by looking if there is another
|
||||
* KRT instance to be initialized later and performing table scan
|
||||
* only once for all the instances.
|
||||
*/
|
||||
* only once for all the instances. */
|
||||
|
||||
/*
|
||||
* If you are brave enough, continue now. You cannot say you haven't been warned.
|
||||
|
|
Loading…
Reference in a new issue