283 lines
13 KiB
ReStructuredText
283 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.
|