summaryrefslogtreecommitdiff
path: root/doc/developer
diff options
context:
space:
mode:
Diffstat (limited to 'doc/developer')
-rw-r--r--doc/developer/.gitignore2
-rw-r--r--doc/developer/Makefile1
-rw-r--r--doc/developer/Makefile.in8
-rw-r--r--doc/developer/building-frr-on-openbsd6.rst2
-rw-r--r--doc/developer/building.rst2
-rw-r--r--doc/developer/conf.py10
-rw-r--r--doc/developer/index.rst6
-rw-r--r--doc/developer/library.rst2
-rw-r--r--doc/developer/packaging-debian.rst173
-rw-r--r--doc/developer/packaging.rst8
-rw-r--r--doc/developer/process-architecture.rst320
11 files changed, 528 insertions, 6 deletions
diff --git a/doc/developer/.gitignore b/doc/developer/.gitignore
index 0505537159..2e7d8573f1 100644
--- a/doc/developer/.gitignore
+++ b/doc/developer/.gitignore
@@ -1,3 +1,3 @@
/_templates
/_build
-!/Makefile
+!/Makefile.in
diff --git a/doc/developer/Makefile b/doc/developer/Makefile
deleted file mode 100644
index 9807a750bf..0000000000
--- a/doc/developer/Makefile
+++ /dev/null
@@ -1 +0,0 @@
-include ../frr-sphinx.mk
diff --git a/doc/developer/Makefile.in b/doc/developer/Makefile.in
new file mode 100644
index 0000000000..76758f9242
--- /dev/null
+++ b/doc/developer/Makefile.in
@@ -0,0 +1,8 @@
+# This is necessary to support VPATH builds.
+srcdir = @srcdir@
+VPATH = @srcdir@
+
+# This variable is used as the documentation source location in frr-sphinx.mk
+SOURCESDIR = @srcdir@
+
+include @srcdir@/../frr-sphinx.mk
diff --git a/doc/developer/building-frr-on-openbsd6.rst b/doc/developer/building-frr-on-openbsd6.rst
index 1f3aec8d92..46db25a025 100644
--- a/doc/developer/building-frr-on-openbsd6.rst
+++ b/doc/developer/building-frr-on-openbsd6.rst
@@ -14,7 +14,7 @@ Add packages:
::
- pkg_add git autoconf-2.69p2 automake-1.15p0 libtool bison
+ pkg_add git autoconf-2.69p2 automake-1.15.1 libtool bison
pkg_add gmake gawk dejagnu openssl json-c py-test py-sphinx
Select Python2.7 as default (required for pytest)
diff --git a/doc/developer/building.rst b/doc/developer/building.rst
index 92fd1bb63a..051611a65d 100644
--- a/doc/developer/building.rst
+++ b/doc/developer/building.rst
@@ -1,3 +1,5 @@
+.. _building:
+
************
Building FRR
************
diff --git a/doc/developer/conf.py b/doc/developer/conf.py
index a3968b60ff..61253c4b2f 100644
--- a/doc/developer/conf.py
+++ b/doc/developer/conf.py
@@ -342,6 +342,14 @@ texinfo_documents = [
# If true, do not generate a @detailmenu in the "Top" node's menu.
#texinfo_no_detailmenu = False
+# contents of ../extra/frrlexer.py.
+# This is read here to support VPATH build. Since this section is execfile()'d
+# with the file location, we can safely use a relative path here to save the
+# contents of the lexer file for later use even if our relative path changes
+# due to VPATH.
+with open('../extra/frrlexer.py', 'rb') as lex:
+ frrlexerpy = lex.read()
+
# custom extensions here
def setup(app):
# object type for FRR CLI commands, can be extended to document parent CLI
@@ -357,5 +365,5 @@ def setup(app):
#
# frrlexer = pygments.lexers.load_lexer_from_file('../extra/frrlexer.py', lexername="FRRLexer")
custom_namespace = {}
- exec(open('../extra/frrlexer.py', 'rb').read(), custom_namespace)
+ exec(frrlexerpy, custom_namespace)
lexers['frr'] = custom_namespace['FRRLexer']()
diff --git a/doc/developer/index.rst b/doc/developer/index.rst
index 17a7e1c0ba..42192db637 100644
--- a/doc/developer/index.rst
+++ b/doc/developer/index.rst
@@ -1,11 +1,13 @@
-Welcome to FRR's documentation!
-===============================
+FRRouting Developer's Guide
+===========================
.. toctree::
:maxdepth: 2
workflow
building
+ packaging
+ process-architecture
library
bgpd
ospf
diff --git a/doc/developer/library.rst b/doc/developer/library.rst
index c5ce1f5982..f6efa33051 100644
--- a/doc/developer/library.rst
+++ b/doc/developer/library.rst
@@ -1,3 +1,5 @@
+.. _libfrr:
+
***************************
Library Facilities (libfrr)
***************************
diff --git a/doc/developer/packaging-debian.rst b/doc/developer/packaging-debian.rst
new file mode 100644
index 0000000000..66339b6d1f
--- /dev/null
+++ b/doc/developer/packaging-debian.rst
@@ -0,0 +1,173 @@
+Debian
+======
+
+(Tested on Ubuntu 12.04, 14.04, 16.04, 17.10, 18.04, Debian 8 and 9)
+
+.. note::
+
+ If you try to build for a different distro, then it will most likely fail
+ because of the missing backport. See :ref:`deb-backports` about adding a new
+ backport.
+
+1. Install build dependencies for your platform as outlined in :ref:`building`.
+
+2. Install the following additional packages:
+
+ - on Ubuntu 12.04, 14.04, 16.04, 17.10, Debian 8 and 9:
+
+ .. code-block:: shell
+
+ apt-get install realpath equivs groff fakeroot debhelper devscripts
+
+ - on Ubuntu 18.04: (realpath is now part of preinstalled by coreutils)
+
+ .. code-block:: shell
+
+ apt-get install equivs groff fakeroot debhelper devscripts
+
+3. Checkout FRR under a **unprivileged** user account:
+
+ .. code-block:: shell
+
+ git clone https://github.com/frrouting/frr.git frr
+ cd frr
+
+ If you wish to build a package for a branch other than master:
+
+ .. code-block:: shell
+
+ git checkout <branch>
+
+4. Run ``bootstrap.sh`` and make a dist tarball:
+
+ .. code-block:: shell
+
+ ./bootstrap.sh
+ ./configure --with-pkg-extra-version=-MyDebPkgVersion
+ make dist
+
+ .. note::
+
+ Configure parameters are not important for the Debian Package building -
+ except the `with-pkg-extra-version` if you want to give the Debian
+ package a specific name to mark your own unoffical build.
+
+5. Edit :file:`debianpkg/rules` and set the configuration as needed.
+
+ Look for section ``dh_auto_configure`` to modify the configure options as
+ needed. Options might be different between the top-level ``rules``` and
+ :file:`backports/XXXX/debian/rules`. Please adjust as needed on all files.
+
+6. Create backports debian sources
+
+ Rename the :file:`debianpkg` directory to :file:`debian` and create the
+ backports (Debian requires to not ship a :file:`debian` directory inside the
+ source directory to avoid build conflicts with the reserved ``debian``
+ subdirectory name during the build):
+
+ .. code-block:: shell
+
+ mv debianpkg debian
+ make -f debian/rules backports
+
+ This will create a :file:`frr_*.orig.tar.gz` with the source (same as the
+ dist tarball), as well as multiple :file:`frr_*.debian.tar.xz` and
+ :file:`frr_*.dsc` corresponding to each distribution for which a backport is
+ available.
+
+7. Create a new directory to build the package and populate with package
+ source.
+
+ .. code-block:: shell
+
+ mkdir frrpkg
+ cd frrpkg
+ tar xf ~/frr/frr_*.orig.tar.gz
+ cd frr*
+ . /etc/os-release
+ tar xf ~/frr/frr_*${ID}${VERSION_ID}*.debian.tar.xz
+
+8. Build Debian package dependencies and install them as needed.
+
+ .. code-block:: shell
+
+ sudo mk-build-deps --install debian/control
+
+9. Build Debian Package
+
+ Building with standard options:
+
+ .. code-block:: shell
+
+ debuild -b -uc -us
+
+ Or change some options (see `rules` file for available options):
+
+ .. code-block:: shell
+
+ debuild --set-envvar=WANT_BGP_VNC=1 --set-envvar=WANT_CUMULUS_MODE=1 -b -uc -us
+
+ To build with RPKI:
+
+ - Download the librtr packages from
+ https://ci1.netdef.org/browse/RPKI-RTRLIB/latestSuccessful/artifact
+
+ - install librtr-dev on the build server
+
+ Then build with:
+
+ .. code-block:: shell
+
+ debuild --set-envvar=WANT_RPKI=1 -b -uc -us
+
+ RPKI packages have an additonal dependency of ``librtr0`` which can be found
+ at the same URL.
+
+10. Done!
+
+If all worked correctly, then you should end up with the Debian packages under
+:file:`frrpkg`. If distributed, please make sure you distribute it together
+with the sources (``frr_*.orig.tar.gz``, ``frr_*.debian.tar.xz`` and
+``frr_*.dsc``)
+
+.. _deb-backports:
+
+Debian Backports
+----------------
+
+The :file:`debianpkg/backports` directory contains the Debian directories for
+backports to other Debian platforms. These are built via the ``3.0 (custom)``
+source format, which allows one to build a source package directly out of
+tarballs (e.g. an orig.tar.gz tarball and a debian.tar.gz file), at which point
+the format can be changed to a real format (e.g. ``3.0 (quilt)``).
+
+Source packages are assembled via targets of the same name as the system to
+which the backport is done (e.g. ``precise``), included in :file:`debian/rules`.
+
+To create a new Debian backport:
+
+- Add its name to ``KNOWN_BACKPORTS``, defined in :file:`debian/rules`.
+- Create a directory of the same name in :file:`debian/backports`.
+- Add the files ``exclude``, ``versionext``, and ``debian/source/format`` under
+ this directory.
+
+For the last point, these files should contain the following:
+
+``exclude``
+ Contains whitespace-separated paths (relative to the root of the source dir)
+ that should be excluded from the source package (e.g.
+ :file:`debian/patches`).
+
+``versionext``
+ Contains the suffix added to the version number for this backport's build.
+ Distributions often have guidelines for what this should be. If left empty,
+ no new :file:`debian/changelog` entry is created.
+
+``debian/source/format``
+ Contains the source format of the resulting source package. As of of the
+ writing of this document the only supported format is ``3.0 (quilt)``.
+
+- Add appropriate files under the :file:`debian/` subdirectory. These will be
+ included in the source package, overriding any top-level :file:`debian/`
+ files with equivalent paths.
+
diff --git a/doc/developer/packaging.rst b/doc/developer/packaging.rst
new file mode 100644
index 0000000000..e9bb3a5409
--- /dev/null
+++ b/doc/developer/packaging.rst
@@ -0,0 +1,8 @@
+*********
+Packaging
+*********
+
+.. toctree::
+ :maxdepth: 2
+
+ packaging-debian
diff --git a/doc/developer/process-architecture.rst b/doc/developer/process-architecture.rst
new file mode 100644
index 0000000000..806afa644c
--- /dev/null
+++ b/doc/developer/process-architecture.rst
@@ -0,0 +1,320 @@
+.. _process-architecture:
+
+Process Architecture
+====================
+
+FRR inherited its overall design architecture from Quagga. The chosen model for
+Quagga is that of a suite of independent daemons that do IPC via Unix domain
+sockets. Within each daemon, the architecture follows the event-driven model.
+FRR has inherited this model as well. As FRR is deployed at larger scales and
+gains ever more features, each adding to the overall processing workload, we
+are approaching the saturation point for a single thread per daemon. In light
+of this, there are ongoing efforts to introduce multithreading to various
+components of FRR. This document aims to describe the current design choices
+and overall model for integrating the event-driven and multithreaded
+architectures into a cohesive whole.
+
+Terminology
+-----------
+Because this document describes the architecture for true kernel threads as
+well as the event system, a digression on terminology is in order here.
+
+Historically Quagga's event system was viewed as an implementation of userspace
+threading. Because of this design choice, the names for various datastructures
+within the event system are variations on the term "thread". The primary
+context datastructure in this system is called a "threadmaster". What would
+today be called an 'event' or 'task' in systems such as libevent are called
+"threads" and the datastructure for them is ``struct thread``. To add to the
+confusion, these "threads" have various types, one of which is "event". To
+hopefully avoid some of this confusion, this document refers to these "threads"
+as a 'task' except where the datastructures are explicitly named. When they are
+explicitly named, they will be formatted ``like this`` to differentiate from
+the conceptual names. When speaking of kernel threads, the term used will be
+"pthread" since FRR's kernel threading implementation is POSIX threads.
+
+.. This should be broken into its document under :ref:`libfrr`
+.. _event-architecture:
+
+Event Architecture
+------------------
+This section presents a brief overview of the event model as currently
+implemented in FRR. This doc should be expanded and broken off into its own
+section. For now it provides basic information necessary to understand the
+interplay between the event system and kernel threads.
+
+The core event system is implemented in :file:`lib/thread.[ch]`. The primary
+structure is ``struct thread_master``, hereafter referred to as a
+``threadmaster``. A ``threadmaster`` is a global state object, or context, that
+holds all the tasks currently pending execution as well as statistics on tasks
+that have already executed. The event system is driven by adding tasks to this
+data structure and then calling a function to retrieve the next task to
+execute. At initialization, a daemon will typically create one
+``threadmaster``, add a small set of initial tasks, and then run a loop to
+fetch each task and execute it.
+
+These tasks have various types corresponding to their general action. The types
+are given by integer macros in :file:`thread.h` and are:
+
+``THREAD_READ``
+ Task which waits for a file descriptor to become ready for reading and then
+ executes.
+
+``THREAD_WRITE``
+ Task which waits for a file descriptor to become ready for writing and then
+ executes.
+
+``THREAD_TIMER``
+ Task which executes after a certain amount of time has passed since it was
+ scheduled.
+
+``THREAD_EVENT``
+ Generic task that executes with high priority and carries an arbitrary
+ integer indicating the event type to its handler. These are commonly used to
+ implement the finite state machines typically found in routing protocols.
+
+``THREAD_READY``
+ Type used internally for tasks on the ready queue.
+
+``THREAD_UNUSED``
+ Type used internally for ``struct thread`` objects that aren't being used.
+ The event system pools ``struct thread`` to avoid heap allocations; this is
+ the type they have when they're in the pool.
+
+``THREAD_EXECUTE``
+ Just before a task is run its type is changed to this. This is used to show
+ ``X`` as the type in the output of :clicmd:`show thread cpu`.
+
+The programmer never has to work with these types explicitly. Each type of task
+is created and queued via special-purpose functions (actually macros, but
+irrelevant for the time being) for the specific type. For example, to add a
+``THREAD_READ`` task, you would call
+
+::
+
+ thread_add_read(struct thread_master *master, int (*handler)(struct thread *), void *arg, int fd, struct thread **ref);
+
+The ``struct thread`` is then created and added to the appropriate internal
+datastructure within the ``threadmaster``.
+
+The Event Loop
+^^^^^^^^^^^^^^
+To use the event system, after creating a ``threadmaster`` the program adds an
+initial set of tasks. As these tasks execute, they add more tasks that execute
+at some point in the future. This sequence of tasks drives the lifecycle of the
+program. When no more tasks are available, the program dies. Typically at
+startup the first task added is an I/O task for VTYSH as well as any network
+sockets needed for peerings or IPC.
+
+To retrieve the next task to run the program calls ``thread_fetch()``.
+``thread_fetch()`` internally computes which task to execute next based on
+rudimentary priority logic. Events (type ``THREAD_EVENT``) execute with the
+highest priority, followed by expired timers and finally I/O tasks (type
+``THREAD_READ`` and ``THREAD_WRITE``). When scheduling a task a function and an
+arbitrary argument are provided. The task returned from ``thread_fetch()`` is
+then executed with ``thread_call()``.
+
+The following diagram illustrates a simplified version of this infrastructure.
+
+.. todo: replace these with SVG
+.. figure:: ../figures/threadmaster-single.png
+ :align: center
+
+ Lifecycle of a program using a single threadmaster.
+
+The series of "task" boxes represents the current ready task queue. The various
+other queues for other types are not shown. The fetch-execute loop is
+illustrated at the bottom.
+
+Mapping the general names used in the figure to specific FRR functions:
+
+- ``task`` is ``struct thread *``
+- ``fetch`` is ``thread_fetch()``
+- ``exec()`` is ``thread_call``
+- ``cancel()`` is ``thread_cancel()``
+- ``schedule()`` is any of the various task-specific ``thread_add_*`` functions
+
+Adding tasks is done with various task-specific function-like macros. These
+macros wrap underlying functions in :file:`thread.c` to provide additional
+information added at compile time, such as the line number the task was
+scheduled from, that can be accessed at runtime for debugging, logging and
+informational purposes. Each task type has its own specific scheduling function
+that follow the naming convention ``thread_add_<type>``; see :file:`thread.h`
+for details.
+
+There are some gotchas to keep in mind:
+
+- I/O tasks are keyed off the file descriptor associated with the I/O
+ operation. This means that for any given file descriptor, only one of each
+ type of I/O task (``THREAD_READ`` and ``THREAD_WRITE``) can be scheduled. For
+ example, scheduling two write tasks one after the other will overwrite the
+ first task with the second, resulting in total loss of the first task and
+ difficult bugs.
+
+- Timer tasks are only as accurate as the monotonic clock provided by the
+ underlying operating system.
+
+- Memory management of the arbitrary handler argument passed in the schedule
+ call is the responsibility of the caller.
+
+
+Kernel Thread Architecture
+--------------------------
+Efforts have begun to introduce kernel threads into FRR to improve performance
+and stability. Naturally a kernel thread architecture has long been seen as
+orthogonal to an event-driven architecture, and the two do have significant
+overlap in terms of design choices. Since the event model is tightly integrated
+into FRR, careful thought has been put into how pthreads are introduced, what
+role they fill, and how they will interoperate with the event model.
+
+Design Overview
+^^^^^^^^^^^^^^^
+Each kernel thread behaves as a lightweight process within FRR, sharing the
+same process memory space. On the other hand, the event system is designed to
+run in a single process and drive serial execution of a set of tasks. With this
+consideration, a natural choice is to implement the event system within each
+kernel thread. This allows us to leverage the event-driven execution model with
+the currently existing task and context primitives. In this way the familiar
+execution model of FRR gains the ability to execute tasks simultaneously while
+preserving the existing model for concurrency.
+
+The following figure illustrates the architecture with multiple pthreads, each
+running their own ``threadmaster``-based event loop.
+
+.. todo: replace these with SVG
+.. figure:: ../figures/threadmaster-multiple.png
+ :align: center
+
+ Lifecycle of a program using multiple pthreads, each running their own
+ ``threadmaster``
+
+Each roundrect represents a single pthread running the same event loop
+described under :ref:`event-architecture`. Note the arrow from the ``exec()``
+box on the right to the ``schedule()`` box in the middle pthread. This
+illustrates code running in one pthread scheduling a task onto another
+pthread's threadmaster. A global lock for each ``threadmaster`` is used to
+synchronize these operations. The pthread names are examples.
+
+
+.. This should be broken into its document under :ref:`libfrr`
+.. _kernel-thread-wrapper:
+
+Kernel Thread Wrapper
+^^^^^^^^^^^^^^^^^^^^^
+The basis for the integration of pthreads and the event system is a lightweight
+wrapper for both systems implemented in :file:`lib/frr_pthread.[ch]`. The
+header provides a core datastructure, ``struct frr_pthread``, that encapsulates
+structures from both POSIX threads and :file:`thread.[ch]`. In particular, this
+datastructure has a pointer to a ``threadmaster`` that runs within the pthread.
+It also has fields for a name as well as start and stop functions that have
+signatures similar to the POSIX arguments for ``pthread_create()``.
+
+Calling ``frr_pthread_new()`` creates and registers a new ``frr_pthread``. The
+returned structure has a pre-initialized ``threadmaster``, and its ``start``
+and ``stop`` functions are initialized to defaults that will run a basic event
+loop with the given threadmaster. Calling ``frr_pthread_run`` starts the thread
+with the ``start`` function. From there, the model is the same as the regular
+event model. To schedule tasks on a particular pthread, simply use the regular
+:file:`thread.c` functions as usual and provide the ``threadmaster`` pointed to
+from the ``frr_pthread``. As part of implementing the wrapper, the
+:file:`thread.c` functions were made thread-safe. Consequently, it is safe to
+schedule events on a ``threadmaster`` belonging both to the calling thread as
+well as *any other pthread*. This serves as the basis for inter-thread
+communication and boils down to a slightly more complicated method of message
+passing, where the messages are the regular task events as used in the
+event-driven model. The only difference is thread cancellation, which requires
+calling ``thread_cancel_async()`` instead of ``thread_cancel`` to cancel a task
+currently scheduled on a ``threadmaster`` belonging to a different pthread.
+This is necessary to avoid race conditions in the specific case where one
+pthread wants to guarantee that a task on another pthread is cancelled before
+proceeding.
+
+In addition, the existing commands to show statistics and other information for
+tasks within the event driven model have been expanded to handle multiple
+pthreads; running :clicmd:`show thread cpu` will display the usual event
+breakdown, but it will do so for each pthread running in the program. For
+example, :ref:`bgpd` runs a dedicated I/O pthread and shows the following
+output for :clicmd:`show thread cpu`:
+
+::
+
+ frr# show thread cpu
+
+ Thread statistics for bgpd:
+
+ Showing statistics for pthread main
+ ------------------------------------
+ CPU (user+system): Real (wall-clock):
+ Active Runtime(ms) Invoked Avg uSec Max uSecs Avg uSec Max uSecs Type Thread
+ 0 1389.000 10 138900 248000 135549 255349 T subgroup_coalesce_timer
+ 0 0.000 1 0 0 18 18 T bgp_startup_timer_expire
+ 0 850.000 18 47222 222000 47795 233814 T work_queue_run
+ 0 0.000 10 0 0 6 14 T update_subgroup_merge_check_thread_cb
+ 0 0.000 8 0 0 117 160 W zclient_flush_data
+ 2 2.000 1 2000 2000 831 831 R bgp_accept
+ 0 1.000 1 1000 1000 2832 2832 E zclient_connect
+ 1 42082.000 240574 174 37000 178 72810 R vtysh_read
+ 1 152.000 1885 80 2000 96 6292 R zclient_read
+ 0 549346.000 2997298 183 7000 153 20242 E bgp_event
+ 0 2120.000 300 7066 14000 6813 22046 T (bgp_holdtime_timer)
+ 0 0.000 2 0 0 57 59 T update_group_refresh_default_originate_route_map
+ 0 90.000 1 90000 90000 73729 73729 T bgp_route_map_update_timer
+ 0 1417.000 9147 154 48000 132 61998 T bgp_process_packet
+ 300 71807.000 2995200 23 3000 24 11066 T (bgp_connect_timer)
+ 0 1894.000 12713 148 45000 112 33606 T (bgp_generate_updgrp_packets)
+ 0 0.000 1 0 0 105 105 W vtysh_write
+ 0 52.000 599 86 2000 138 6992 T (bgp_start_timer)
+ 1 1.000 8 125 1000 164 593 R vtysh_accept
+ 0 15.000 600 25 2000 15 153 T (bgp_routeadv_timer)
+ 0 11.000 299 36 3000 53 3128 RW bgp_connect_check
+
+
+ Showing statistics for pthread BGP I/O thread
+ ----------------------------------------------
+ CPU (user+system): Real (wall-clock):
+ Active Runtime(ms) Invoked Avg uSec Max uSecs Avg uSec Max uSecs Type Thread
+ 0 1611.000 9296 173 13000 188 13685 R bgp_process_reads
+ 0 2995.000 11753 254 26000 182 29355 W bgp_process_writes
+
+
+ Showing statistics for pthread BGP Keepalives thread
+ -----------------------------------------------------
+ CPU (user+system): Real (wall-clock):
+ Active Runtime(ms) Invoked Avg uSec Max uSecs Avg uSec Max uSecs Type Thread
+ No data to display yet.
+
+Attentive readers will notice that there is a third thread, the Keepalives
+thread. This thread is responsible for -- surprise -- generating keepalives for
+peers. However, there are no statistics showing for that thread. Although the
+pthread uses the ``frr_pthread`` wrapper, it opts not to use the embedded
+``threadmaster`` facilities. Instead it replaces the ``start`` and ``stop``
+functions with custom functions. This was done because the ``threadmaster``
+facilities introduce a small but significant amount of overhead relative to the
+pthread's task. In this case since the pthread does not need the event-driven
+model and does not need to receive tasks from other pthreads, it is simpler and
+more efficient to implement it outside of the provided event facilities. The
+point to take away from this example is that while the facilities to make using
+pthreads within FRR easy are already implemented, the wrapper is flexible and
+allows usage of other models while still integrating with the rest of the FRR
+core infrastructure. Starting and stopping this pthread works the same as it
+does for any other ``frr_pthread``; the only difference is that event
+statistics are not collected for it, because there are no events.
+
+Notes on Design and Documentation
+---------------------------------
+Because of the choice to embed the existing event system into each pthread
+within FRR, at this time there is not integrated support for other models of
+pthread use such as divide and conquer. Similarly, there is no explicit support
+for thread pooling or similar higher level constructs. The currently existing
+infrastructure is designed around the concept of long-running worker threads
+responsible for specific jobs within each daemon. This is not to say that
+divide and conquer, thread pooling, etc. could not be implemented in the
+future. However, designs in this direction must be very careful to take into
+account the existing codebase. Introducing kernel threads into programs that
+have been written under the assumption of a single thread of execution must be
+done very carefully to avoid insidious errors and to ensure the program remains
+understandable and maintainable.
+
+In keeping with these goals, future work on kernel threading should be
+extensively documented here and FRR developers should be very careful with
+their design choices, as poor choices tightly integrated can prove to be
+catastrophic for development efforts in the future.