282 lines
13 KiB
ReStructuredText
282 lines
13 KiB
ReStructuredText
Architecture
|
||
============
|
||
|
||
Introduction
|
||
------------
|
||
|
||
The goal of the new northbound API is to provide a better interface to
|
||
configure and monitor FRR programatically. The current design based on
|
||
CLI commands is no longer adequate in a world where computer networks
|
||
are becoming increasingly bigger, more diverse and more complex. Network
|
||
scripting using *expect* and screen scraping techniques is too primitive
|
||
and unreliable to be used in large-scale networks. What is proposed is
|
||
to modernize FRR to turn it into an API-first routing stack, and
|
||
reposition the CLI on top of this API. The most important change,
|
||
however, is not the API that will be provided to external users. In
|
||
fact, multiple APIs will be supported and users will have the ability to
|
||
write custom management APIs if necessary. The biggest change is the
|
||
introduction of a model-driven management architecture based on the
|
||
`YANG <https://tools.ietf.org/html/rfc7950>`__ modeling language.
|
||
Instead of writing code tied to any particular user interface
|
||
(e.g. DEFUNs), YANG allows us to write API-agnostic code (in the form of
|
||
callbacks) that can be used by any management interface. As an example,
|
||
it shouldn’t matter if a set of configuration changes is coming from a
|
||
`NETCONF <https://tools.ietf.org/html/rfc6241>`__ session or from a CLI
|
||
terminal, the same callbacks should be called to process the
|
||
configuration changes regardless of where they came from. This
|
||
model-driven design ensures feature parity across all management
|
||
interfaces supported by FRR.
|
||
|
||
Quoting :rfc:`7950`:
|
||
|
||
YANG is a language originally designed to model data for the NETCONF
|
||
protocol. A YANG module defines hierarchies of data that can be used for
|
||
NETCONF-based operations, including configuration, state data, RPCs, and
|
||
notifications. This allows a complete description of all data sent between a
|
||
NETCONF client and server. Although out of scope for this specification,
|
||
YANG can also be used with protocols other than NETCONF.
|
||
|
||
While the YANG and NETCONF specifications are tightly coupled with one
|
||
another, both are independent to a certain extent and are evolving
|
||
separately. Examples of other management protocols that use YANG include
|
||
`RESTCONF <https://tools.ietf.org/html/rfc8040>`__,
|
||
`gNMI <https://github.com/openconfig/reference/tree/master/rpc/gnmi>`__
|
||
and
|
||
`CoAP <https://www.ietf.org/archive/id/draft-vanderstok-core-comi-11.txt>`__.
|
||
|
||
In addition to being management-protocol independent, some other
|
||
advantages of using YANG in FRR are listed below:
|
||
|
||
* Have a formal contract between FRR and application developers (management
|
||
clients). A management client that has access to the FRR YANG models knows
|
||
about all existing configuration options available for use. This information
|
||
can be used to auto-generate user-friendly interfaces like Web-UIs, custom
|
||
CLIs and even code bindings for several different programming languages. Using
|
||
`PyangBind <https://github.com/robshakir/pyangbind>`__, for example, it’s
|
||
possible to generate Python class hierarchies from YANG models and use these
|
||
classes to instantiate objects that mirror the structure of the YANG modules
|
||
and can be serialized/deserialized using different encoding formats.
|
||
|
||
* Support different encoding formats for instance data. Currently only JSON and
|
||
XML are supported, but `GPB
|
||
<https://developers.google.com/protocol-buffers/>`__ and `CBOR
|
||
<http://cbor.io/>`__ are other viable options in the long term. Additional
|
||
encoding formats can be implemented in the *libyang* library for optimal
|
||
performance, or externally by translating data to/from one of the supported
|
||
formats (with a performance penalty).
|
||
|
||
* Have a formal mechanism to introduce backward-incompatible changes based on
|
||
`semantic versioning <http://www.openconfig.net/docs/semver/>`__ (not part of
|
||
the YANG standard, which allows backward-compatible module updates only).
|
||
|
||
* Provide seamless support to the industry-standard NETCONF/RESTCONF protocols
|
||
as alternative management APIs. If FRR configuration/state data is modeled
|
||
using YANG, supporting YANG-based protocols like NETCONF and RESTCONF is much
|
||
easier.
|
||
|
||
As important as shifting to a model-driven management paradigm, the new
|
||
northbound architecture also introduces the concept of configuration
|
||
transactions. Configuration transactions allow management clients to
|
||
commit multiple configuration changes at the same time and rest assured
|
||
that either all changes will be applied or none will (all-or-nothing).
|
||
Configuration transactions are implemented as pseudo-atomic operations
|
||
and facilitate automation by removing the burden of error recovery from
|
||
the management side. Another property of configuration transactions is
|
||
that the configuration changes are always processed in a pre-defined
|
||
order to ensure consistency. Configuration transactions that encompass
|
||
multiple network devices are called network-wide transactions and are
|
||
also supported by the new northbound architecture. When FRR is built
|
||
using the ``--enable-config-rollbacks`` option, all committed
|
||
transactions are recorded in the FRR rollback log, which can reside
|
||
either in memory (volatile) or on persistent storage.
|
||
|
||
Network-wide Transactions is the most important leap in network
|
||
management technology since SNMP. The error recovery and sequencing
|
||
tasks are removed from the manager side. This is usually more than
|
||
half the cost in a mature system; more than the entire cost of the
|
||
managed devices.
|
||
`[source] <https://www.nanog.org/sites/default/files/tuesday_tutorial_moberg_netconf_35.pdf>`__.
|
||
|
||
Figures 1 and 2 below illustrate the old and new northbound architecture
|
||
of FRR, respectively. As it can be seen, in the old architecture the CLI
|
||
was the only interface used to configure and monitor FRR (the SNMP
|
||
plugin was’t taken into account given the small number of implemented
|
||
MIBs). This means that the only way to automate FRR was by writing
|
||
scripts that send CLI commands and parse the text output (which usually
|
||
doesn’t have any structure) using screen scraping and regular
|
||
expressions.
|
||
|
||
.. figure:: images/arch-before.png
|
||
:alt: diagram of northbound architecture prior to nbapi conversion
|
||
|
||
Old northbound architecture
|
||
|
||
The new northbound architectures, on the other hand, features a
|
||
multitude of different management APIs, all of them connected to the
|
||
northbound layer of the FRR daemons. By default, only the CLI interface
|
||
is compiled built-in in the FRR daemons. The other management interfaces
|
||
are provided as optional plugins and need to be loaded during the daemon
|
||
initialization (e.g. *zebra -M grpc*). This design makes it possible to
|
||
integrate FRR with different NETCONF solutions without introducing
|
||
vendor lock-in. The [[Plugins - Writing Your Own]] page explains how to
|
||
write custom northbound plugins that can be tailored to all needs
|
||
(e.g. support custom transport protocols, different data encoding
|
||
formats, fine-grained access control, etc).
|
||
|
||
.. figure:: images/arch-after.png
|
||
:alt: diagram of northbound architecture after nbapi conversion
|
||
|
||
New northbound architecture
|
||
|
||
Figure 3 shows the internal view of the FRR northbound architecture. In
|
||
this image we can see that northbound layer is an abstract entity
|
||
positioned between the northbound callbacks and the northbound clients.
|
||
The northbound layer is responsible to process the requests coming from
|
||
the northbound clients and call the appropriate callbacks to satisfy
|
||
these requests. The northbound plugins communicate with the northbound
|
||
layer through a public API, which allow users to write third-party
|
||
plugins that can be maintained separately. The northbound plugins, in
|
||
turn, have their own APIs to communicate with external management
|
||
clients.
|
||
|
||
.. figure:: images/nb-layer.png
|
||
:alt: diagram of northbound architecture internals
|
||
|
||
New northbound architecture - internal view
|
||
|
||
Initially the CLI (and all of its commands) will be maintained inside
|
||
the FRR daemons. In the long term, however, the goal is to move the CLI
|
||
to a separate program just like any other management client. The
|
||
[[Advanced Topics]] page describes the motivations and challenges of
|
||
doing that. Last but not least, the *libyang* block inside the
|
||
northbound layer is the engine that makes everything possible. The
|
||
*libyang* library will be described in more detail in the following
|
||
sections.
|
||
|
||
YANG models
|
||
-----------
|
||
|
||
The main decision to be made when using YANG is which models to
|
||
implement. There’s a general consensus that using standard models is
|
||
preferable over using custom (native) models. The reasoning is that
|
||
applications based on standard models can be reused for all network
|
||
appliances that support those models, whereas the same doesn’t apply for
|
||
applications written based on custom models.
|
||
|
||
That said, there are multiple standards bodies publishing YANG models
|
||
and unfortunately not all of them are converging (or at least not yet).
|
||
In the context of FRR, which is a routing stack, the two sets of YANG
|
||
models that would make sense to implement are the ones from IETF and
|
||
from the OpenConfig working group. The question that arises is: which
|
||
one of them should we commit to? Or should we try to support both
|
||
somehow, at the cost of extra development efforts?
|
||
|
||
Another problem, from an implementation point of view, is that it’s
|
||
challenging to adapt the existing code base to match standard models. A
|
||
more reasonable solution, at least in a first moment, would be to use
|
||
YANG deviations and augmentations to do the opposite: adapt the standard
|
||
models to the existing code. In practice however this is not as simple
|
||
as it seems. There are cases where the differences are too substantial
|
||
to be worked around without restructuring the code by changing its data
|
||
structures and their relationships. As an example, the *ietf-rip* model
|
||
places per-interface RIP configuration parameters inside the
|
||
*control-plane-protocol* list (which is augmented by *ietf-rip*). This
|
||
means that it’s impossible to configure RIP interface parameters without
|
||
first configuring a RIP routing instance. The *ripd* daemon on the other
|
||
hand allows the operator to configure RIP interface parameters even if
|
||
``router rip`` is not configured. If we were to implement the *ietf-rip*
|
||
module natively, we’d need to change ripd’s CLI commands (and the
|
||
associated code) to reflect the new configuration hierarchy.
|
||
|
||
Taking into account that FRR has a huge code base and that the
|
||
northbound retrofitting process per-se will cause a lot of impact, it
|
||
was decided to take a conservative approach and write custom YANG models
|
||
for FRR modeled after the existing CLI commands. Having YANG models that
|
||
closely mirror the CLI commands will allow the FRR developers to
|
||
retrofit the code base much more easily, without introducing
|
||
backward-incompatible changes in the CLI and reducing the likelihood of
|
||
introducing bugs. The [[Retrofitting Configuration Commands]] page
|
||
explains in detail how to convert configuration commands to the new
|
||
northbound model.
|
||
|
||
Even though having native YANG models is not the ideal solution, it will
|
||
be already a big step forward for FRR to migrate to a model-driven
|
||
management architecture, with support for configuration transactions and
|
||
multiple management interfaces, including NETCONF and RESTCONF (through
|
||
the northbound plugins).
|
||
|
||
The new northbound also features an experimental YANG module translator
|
||
that will allow users to translate to and from standard YANG models by
|
||
using translation tables. The [[YANG module translator]] page describes
|
||
this mechanism in more detail. At this point it’s unclear what can be
|
||
achieved through module translation and if that can be considered as a
|
||
definitive solution to support standard models or not.
|
||
|
||
Northbound Architecture
|
||
-----------------------
|
||
|
||
.. figure:: images/lys-node.png
|
||
:alt: diagram of libyanbg's lys_node data structure
|
||
|
||
``libyang's`` lys_node data structure
|
||
|
||
|
||
.. figure:: images/lyd-node.png
|
||
:alt: diagram of libyanbg's lyd_node data structure
|
||
|
||
``libyang's`` lyd_node data structure
|
||
|
||
|
||
.. figure:: images/ly-ctx.png
|
||
:alt: diagram of libyanbg's ly_ctx data structure
|
||
|
||
``libyang's`` ly_ctx data structure
|
||
|
||
|
||
.. figure:: images/transactions.png
|
||
:alt: diagram showing how configuration transactions work
|
||
|
||
Configuration transactions
|
||
|
||
|
||
Testing
|
||
-------
|
||
|
||
The new northbound adds the libyang library as a new mandatory
|
||
dependency for FRR. To obtain and install this library, follow the steps
|
||
below:
|
||
|
||
.. code-block:: console
|
||
|
||
git clone https://github.com/CESNET/libyang
|
||
cd libyang
|
||
git checkout devel
|
||
mkdir build ; cd build
|
||
cmake -DENABLE_LYD_PRIV=ON ..
|
||
make
|
||
sudo make install
|
||
|
||
|
||
.. note::
|
||
|
||
first make sure to install the libyang
|
||
`requirements <https://github.com/CESNET/libyang#build-requirements>`__.
|
||
|
||
|
||
FRR needs libyang from version 0.16.7 or newer, which is maintained in
|
||
the ``devel`` branch. libyang 0.15.x is maintained in the ``master``
|
||
branch and doesn’t contain one small feature used by FRR (the
|
||
``LY_CTX_DISABLE_SEARCHDIR_CWD`` flag). FRR also makes use of the
|
||
libyang’s ``ENABLE_LYD_PRIV`` feature, which is disabled by default and
|
||
needs to be enabled at compile time.
|
||
|
||
It’s advisable (but not required) to install sqlite3 and build FRR with
|
||
``--enable-config-rollbacks`` in order to have access to the
|
||
configuration rollback feature.
|
||
|
||
To test the northbound, the suggested method is to use the
|
||
[[Transactional CLI]] with the *ripd* daemon and play with the new
|
||
commands. The ``debug northbound`` command can be used to see which
|
||
northbound callbacks are called in response to the ``commit`` command.
|
||
For reference, the [[Demos]] page shows a small demonstration of the
|
||
transactional CLI in action and what it’s capable of.
|