diff options
Diffstat (limited to 'doc')
37 files changed, 3230 insertions, 115 deletions
diff --git a/doc/developer/building.rst b/doc/developer/building.rst index a6cd545872..c687ba8dc8 100644 --- a/doc/developer/building.rst +++ b/doc/developer/building.rst @@ -29,3 +29,4 @@ Building FRR building-frr-for-ubuntu2004 building-frr-for-archlinux building-docker + cross-compiling diff --git a/doc/developer/cross-compiling.rst b/doc/developer/cross-compiling.rst new file mode 100644 index 0000000000..339e00c921 --- /dev/null +++ b/doc/developer/cross-compiling.rst @@ -0,0 +1,326 @@ +Cross-Compiling +=============== + +FRR is capable of being cross-compiled to a number of different architectures. +With an adequate toolchain this process is fairly straightforward, though one +must exercise caution to validate this toolchain's correctness before attempting +to compile FRR or its dependencies; small oversights in the construction of the +build tools may lead to problems which quickly become difficult to diagnose. + +Toolchain Preliminary +--------------------- + +The first step to cross-compiling any program is to identify the system which +the program (FRR) will run on. From here on this will be called the "host" +machine, following autotools' convention, while the machine building FRR will be +called the "build" machine. The toolchain will of course be installed onto the +build machine and be leveraged to build FRR for the host machine to run. + +.. note:: + + The build machine used while writing this guide was ``x86_64-pc-linux-gnu`` + and the target machine was ``arm-linux-gnueabihf`` (a Raspberry Pi 3B+). + Replace this with your targeted tuple below if you plan on running the + commands from this guide: + + .. code-block:: shell + + export HOST_ARCH="arm-linux-gnueabihf" + + For your given target, the build system's OS may have some support for + building cross compilers natively, or may even offer binary toolchains built + upstream for the target architecture. Check your package manager or OS + documentation before committing to building a toolchain from scratch. + +This guide will not detail *how* to build a cross-compiling toolchain but +will instead assume one already exists and is installed on the build system. +The methods for building the toolchain itself may differ between operating +systems so consult the OS documentation for any particulars regarding +cross-compilers. The OSDev wiki has a `pleasant tutorial`_ on cross-compiling in +the context of operating system development which bootstraps from only the +native GCC and binutils on the build machine. This may be useful if the build +machine's OS does not offer existing tools to build a cross-compiler targeting +the host. + +.. _pleasant tutorial: https://wiki.osdev.org/GCC_Cross-Compiler + +This guide will also not demonstrate how to build all of FRR's dependencies for the +target architecture. Instead, general instructions for using a cross-compiling +toolchain to compile packages using CMake, Autotools, and Makefiles are +provided; these three cases apply to almost all FRR dependencies. + +.. _glibc mismatch: + +.. warning:: + + Ensure the versions and implementations of the C standard library (glibc or + what have you) match on the host and the build toolchain. ``ldd --version`` + will help you here. Upgrade one or the other if the they do not match. + +Testing the Toolchain +--------------------- + +Before any cross-compilation begins it would be prudent to test the new +toolchain by writing, compiling and linking a simple program. + +.. code-block:: shell + + # A small program + cat > nothing.c <<EOF + int main() { return 0; } + EOF + + # Build and link with the cross-compiler + ${HOST_ARCH}-gcc -o nothing nothing.c + + # Inspect the resulting binary, results may vary + file ./nothing + + # nothing: ELF 32-bit LSB pie executable, ARM, EABI5 version 1 (SYSV), + # dynamically linked, interpreter /lib/ld-linux-armhf.so.3, + # for GNU/Linux 3.2.0, not stripped + +If this produced no errors then the installed toolchain is probably ready to +start compiling the build dependencies and eventually FRR itself. There still +may be lurking issues but fundamentally the toolchain can produce binaries and +that's good enough to start working with it. + +.. warning:: + + If any errors occurred during the previous functional test please look back + and address them before moving on; this indicates your cross-compiling + toolchain is *not* in a position to build FRR or its dependencies. Even if + everything was fine, keep in mind that many errors from here on *may still + be related* to your toolchain (e.g. libstdc++.so or other components) and this + small test is not a guarantee of complete toolchain coherence. + +Cross-compiling Dependencies +---------------------------- + +When compiling FRR it is necessary to compile some of its dependencies alongside +it on the build machine. This is so symbols from the shared libraries (which +will be loaded at run-time on the host machine) can be linked to the FRR +binaries at compile time; additionally, headers for these libraries are needed +during the compile stage for a successful build. + +Sysroot Overview +^^^^^^^^^^^^^^^^ + +All build dependencies should be installed into a "root" directory on the build +computer, hereafter called the "sysroot". This directory will be prefixed to +paths while searching for requisite libraries and headers during the build +process. Often this may be set via a ``--prefix`` flag when building the +dependent packages, meaning a ``make install`` will copy compiled libraries into +(e.g.) ``/usr/${HOST_ARCH}/usr``. + +If the toolchain was built on the build machine then there is likely already a +sysroot where those tools and standard libraries were installed; it may be +helpful to use that directory as the sysroot for this build as well. + +Basic Workflow +^^^^^^^^^^^^^^ + +Before compiling or building any dependencies, make note of which daemons are +being targeted and which libraries will be needed. Not all dependencies are +necessary if only building with a subset of the daemons. + +The following workflow will compile and install any libraries which can be built +with Autotools. The resultant library will be installed into the sysroot +``/usr/${HOST_ARCH}``. + +.. code-block:: shell + + ./configure \ + CC=${HOST_ARCH}-gcc \ + CXX=${HOST_ARCH}-g++ \ + --build=${HOST_ARCH} \ + --prefix=/usr/${HOST_ARCH} + make + make install + +Some libraries like ``json-c`` and ``libyang`` are packaged with CMake and can +be built and installed generally like: + +.. code-block:: shell + + mkdir build + cd build + CC=${HOST_ARCH}-gcc \ + CXX=${HOST_ARCH}-g++ \ + cmake \ + -DCMAKE_INSTALL_PREFIX=/usr/${HOST_ARCH} \ + .. + make + make install + +For programs with only a Makefile (e.g. ``libcap``) the process may look still a +little different: + +.. code-block:: shell + + CC=${HOST_ARCH}-gcc make + make install DESTDIR=/usr/${HOST_ARCH} + +These three workflows should handle the bulk of building and installing the +build-time dependencies for FRR. Verify that the installed files are being +placed correctly into the sysroot and were actually built using the +cross-compile toolchain, not by the native toolchain by accident. + +Dependency Notes +^^^^^^^^^^^^^^^^ + +There are a lot of things that can go wrong during a cross-compilation. Some of +the more common errors and a few special considerations are collected below for +reference. + +libyang +""""""" + +``-DENABLE_LYD_PRIV=ON`` should be provided during the CMake step. + +Ensure also that the version of ``libyang`` being installed corresponds to the +version required by the targeted FRR version. + +gRPC +"""" + +This piece is requisite only if the ``--enable-grpc`` flag will be passed +later on to FRR. One may get burned when compiling gRPC if the ``protoc`` +version on the build machine differs from the version of ``protoc`` being linked +to during a gRPC build. The error messages from this defect look like: + +.. code-block:: terminal + + gens/src/proto/grpc/channelz/channelz.pb.h: In member function ‘void grpc::channelz::v1::ServerRef::set_name(const char*, size_t)’: + gens/src/proto/grpc/channelz/channelz.pb.h:9127:64: error: ‘EmptyDefault’ is not a member of ‘google::protobuf::internal::ArenaStringPtr’ + 9127 | name_.Set(::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::EmptyDefault{}, ::std::string( + +This happens because protocol buffer code generation uses ``protoc`` to create +classes with different getters and setters corresponding to the protobuf data +defined by the source tree's ``.proto`` files. Clearly the cross-compiled +``protoc`` cannot be used for this code generation because that binary is built +for a different CPU. + +The solution is to install matching versions of native and cross-compiled +protocol buffers; this way the native binary will generate code and the +cross-compiled library will be linked to by gRPC and these versions will not +disagree. + +---- + +The ``-latomic`` linker flag may also be necessary here if using ``libstdc++`` +since GCC's C++11 implementation makes library calls in certain cases for +``<atomic>`` so ``-latomic`` cannot be assumed. + +Cross-compiling FRR Itself +-------------------------- + +With all the necessary libraries cross-compiled and installed into the sysroot, +the last thing to actually build is FRR itself: + +.. code-block:: shell + + # Clone and bootstrap the build + git clone 'https://github.com/FRRouting/frr.git' + # (e.g.) git checkout stable/7.5 + ./bootstrap.sh + + # Build clippy using the native toolchain + mkdir build-clippy + cd build-clippy + ../configure --enable-clippy-only + make clippy-only + cd .. + + # Next, configure FRR and use the clippy we just built + ./configure \ + CC=${HOST_ARCH}-gcc \ + CXX=${HOST_ARCH}-g++ \ + --host=${HOST_ARCH} \ + --with-sysroot=/usr/${HOST_ARCH} \ + --with-clippy=./build-clippy/lib/clippy \ + --sysconfdir=/etc/frr \ + --sbindir="\${prefix}/lib/frr" \ + --localstatedir=/var/run/frr \ + --prefix=/usr \ + --enable-user=frr \ + --enable-group=frr \ + --enable-vty-group=frrvty \ + --disable-doc \ + --enable-grpc + + # Send it + make + +Installation to Host Machine +---------------------------- + +If no errors were observed during the previous steps it is safe to ``make +install`` FRR into its own directory. + +.. code-block:: shell + + # Install FRR its own "sysroot" + make install DESTDIR=/some/path/to/sysroot + +After running the above command, FRR binaries, modules and example configuration +files will be installed into some path on the build machine. The directory +will have folders like ``/usr`` and ``/etc``; this "root" should now be copied +to the host and installed on top of the root directory there. + +.. code-block:: shell + + # Tar this sysroot (preserving permissions) + tar -C /some/path/to/sysroot -cpvf frr-${HOST_ARCH}.tar . + + # Transfer tar file to host machine + scp frr-${HOST_ARCH}.tar me@host-machine: + + # Overlay the tarred sysroot on top of the host machine's root + ssh me@host-machine <<-EOF + # May need to elevate permissions here + tar -C / -xpvf frr-${HOST_ARCH}.tar.gz . + EOF + +Now FRR should be installed just as if ``make install`` had been run on the host +machine. Create configuration files and assign permissions as needed. Lastly, +ensure the correct users and groups exist for FRR on the host machine. + +Troubleshooting +--------------- + +Even when every precaution has been taken some things may still go wrong! This +section details some common runtime problems. + +Mismatched Libraries +^^^^^^^^^^^^^^^^^^^^ + +If you see something like this after installing on the host: + +.. code-block:: console + + /usr/lib/frr/zebra: error while loading shared libraries: libyang.so.1: cannot open shared object file: No such file or directory + +... at least one of FRR's dependencies which was linked to the binary earlier is +not available on the host OS. Even if it has been installed the host +repository's version may lag what is needed for more recent FRR builds (this is +likely to happen with YANG at the moment). + +If the matching library is not available from the host OS package manager it may +be possible to compile them using the same toolchain used to compile FRR. The +library may have already been built earlier when compiling FRR on the build +machine, in which case it may be as simple as following the same workflow laid +out during the `Installation to Host Machine`_. + +Mismatched Glibc Versions +^^^^^^^^^^^^^^^^^^^^^^^^^ + +The version and implementation of the C standard library must match on both the +host and build toolchain. The error corresponding to this misconfiguration will +look like: + +.. code-block:: console + + /usr/lib/frr/zebra: /lib/${HOST_ARCH}/libc.so.6: version `GLIBC_2.32' not found (required by /usr/lib/libfrr.so.0) + +See the earlier warning about preventing a `glibc mismatch`_. diff --git a/doc/developer/index.rst b/doc/developer/index.rst index 5a7da806ff..8e7913419f 100644 --- a/doc/developer/index.rst +++ b/doc/developer/index.rst @@ -18,3 +18,5 @@ FRRouting Developer's Guide ospf zebra vtysh + path + link-state diff --git a/doc/developer/library.rst b/doc/developer/library.rst index 3d5c6a2a15..2e36c253ea 100644 --- a/doc/developer/library.rst +++ b/doc/developer/library.rst @@ -11,10 +11,11 @@ Library Facilities (libfrr) rcu lists logging + xrefs locking hooks cli modules - lua + scripting diff --git a/doc/developer/link-state.rst b/doc/developer/link-state.rst new file mode 100644 index 0000000000..f1fc52966b --- /dev/null +++ b/doc/developer/link-state.rst @@ -0,0 +1,314 @@ +Link State API Documentation +============================ + +Introduction +------------ + +The Link State (LS) API aims to provide a set of structures and functions to +build and manage a Traffic Engineering Database for the various FRR daemons. +This API has been designed for several use cases: + +- BGP Link State (BGP-LS): where BGP protocol need to collect the link state + information from the routing daemons (IS-IS and/or OSPF) to implement RFC7572 +- Path Computation Element (PCE): where path computation algorithms are based + on Traffic Engineering Database +- ReSerVation Protocol (RSVP): where signaling need to know the Traffic + Engineering topology of the network in order to determine the path of + RSVP tunnels + +Architecture +------------ + +The main requirements from the various uses cases are as follow: + +- Provides a set of data model and function to ease Link State information + manipulation (storage, serialize, parse ...) +- Ease and normalize Link State information exchange between FRR daemons +- Provides database structure for Traffic Engineering Database (TED) + +To ease Link State understanding, FRR daemons have been classified into two +categories: + +- **Consumer**: Daemons that consume Link State information e.g. BGPd +- **Producer**: Daemons that are able to collect Link State information and + send them to consumer daemons e.g. OSPFd IS-ISd + +Zebra daemon, and more precisely, the ZAPI message is used to convey the Link +State information between *producer* and *consumer*, but, Zebra acts as a +simple pass through and does not store any Link State information. A new ZAPI +**Opaque** message has been design for that purpose. + +Each consumer and producer daemons are free to store or not Link State data and +organise the information following the Traffic Engineering Database model +provided by the API or any other data structure e.g. Hash, RB-tree ... + +Link State API +-------------- + +This is the low level API that allows any daemons manipulate the Link State +elements that are stored in the Link State Database. + +Data structures +^^^^^^^^^^^^^^^ + +3 types of Link State structure have been defined: + +.. c:type:: struct ls_node + + that groups all information related to a node + +.. c:type:: struct ls_attributes + + that groups all information related to a link + +.. c:type:: struct ls_prefix + + that groups all information related to a prefix + +These 3 types of structures are those handled by BGP-LS (see RFC7752) and +suitable to describe a Traffic Engineering topology. + +Each structure, in addition to the specific parameters, embed the node +identifier which advertises the Link State and a bit mask as flags to +indicates which parameters are valid i.e. for which the value is valid and +corresponds to a Link State information conveyed by the routing protocol. + +.. c:type:: struct ls_node_id + + defines the Node identifier as router ID IPv4 address plus the area ID for + OSPF or the ISO System ID plus the IS-IS level for IS-IS. + +Functions +^^^^^^^^^ + +A set of functions is provided to create, delete and compare Link State Node: + +.. c:function:: struct ls_node *ls_node_new(struct ls_node_id adv, struct in_addr router_id, struct in6_addr router6_id) +.. c:function:: voidls_node_del(struct ls_node *node) +.. c:function:: int ls_node_same(struct ls_node *n1, struct ls_node *n2) + +and Link State Attributes: + +.. c:function:: struct ls_attributes *ls_attributes_new(struct ls_node_id adv, struct in_addr local, struct in6_addr local6, uint32_t local_id) +.. c:function:: void ls_attributes_del(struct ls_attributes *attr) +.. c:function:: int ls_attributes_same(struct ls_attributes *a1, struct ls_attributes *a2) + +The low level API doesn't provide any particular functions for the Link State +Prefix structure as this latter is simpler to manipulate. + +Link State TED +-------------- + +This is the high level API that provides functions to create, update, delete a +Link State Database to from a Traffic Engineering Database (TED). + +Data Structures +^^^^^^^^^^^^^^^ + +The Traffic Engineering is modeled as a Graph in order to ease Path Computation +algorithm implementation. Denoted **G(V, E)**, a graph is composed by a list of +**Vertices (V)** which represents the network Node and a list of **Edges (E)** +which represents Link. An additional list of **prefixes (P)** is also added and +also attached to the *Vertex (V)* which advertise it. + +*Vertex (V)* contains the list of outgoing *Edges (E)* that connect this Vertex +with its direct neighbors and the list of incoming *Edges (E)* that connect +the direct neighbors to this Vertex. Indeed, the *Edge (E)* is unidirectional, +thus, it is necessary to add 2 Edges to model a bidirectional relation between +2 Vertices. Finally, the *Vertex (V)* contains a pointer to the corresponding +Link State Node. + +*Edge (E)* contains the source and destination Vertex that this Edge +is connecting and a pointer to the corresponding Link State Attributes. + +A unique Key is used to identify both Vertices and Edges within the Graph. + + +:: + + -------------- --------------------------- -------------- + | Connected |---->| Connected Edge Va to Vb |--->| Connected | + --->| Vertex | --------------------------- | Vertex |----> + | | | | + | - Key (Va) | | - Key (Vb) | + <---| - Vertex | --------------------------- | - Vertex |<---- + | |<----| Connected Edge Vb to Va |<---| | + -------------- --------------------------- -------------- + + +4 data structures have been defined to implement the Graph model: + +.. c:type:: struct ls_vertex +.. c:type:: struct ls_edge +.. c:type:: struct ls_prefix +.. c:type:: struct ls_ted + + +Functions +^^^^^^^^^ + +.. c:function:: struct ls_vertex *ls_vertex_add(struct ls_ted *ted, struct ls_node *node) +.. c:function:: struct ls_vertex *ls_vertex_update(struct ls_ted *ted, struct ls_node *node) +.. c:function:: void ls_vertex_del(struct ls_ted *ted, struct ls_vertex *vertex) +.. c:function:: struct ls_vertex *ls_find_vertex_by_key(struct ls_ted *ted, const uint64_t key) +.. c:function:: struct ls_vertex *ls_find_vertex_by_id(struct ls_ted *ted, struct ls_node_id id) +.. c:function:: int ls_vertex_same(struct ls_vertex *v1, struct ls_vertex *v2) + +.. c:function:: struct ls_edge *ls_edge_add(struct ls_ted *ted, struct ls_attributes *attributes) +.. c:function:: struct ls_edge *ls_edge_update(struct ls_ted *ted, struct ls_attributes *attributes) +.. c:function:: void ls_edge_del(struct ls_ted *ted, struct ls_edge *edge) +.. c:function:: struct ls_edge *ls_find_edge_by_key(struct ls_ted *ted, const uint64_t key) +.. c:function:: struct ls_edge *ls_find_edge_by_source(struct ls_ted *ted, struct ls_attributes *attributes); +.. c:function:: struct ls_edge *ls_find_edge_by_destination(struct ls_ted *ted, struct ls_attributes *attributes); + +.. c:function:: struct ls_subnet *ls_subnet_add(struct ls_ted *ted, struct ls_prefix *pref) +.. c:function:: void ls_subnet_del(struct ls_ted *ted, struct ls_subnet *subnet) +.. c:function:: struct ls_subnet *ls_find_subnet(struct ls_ted *ted, const struct prefix prefix) + +.. c:function:: struct ls_ted *ls_ted_new(const uint32_t key, char *name, uint32_t asn) +.. c:function:: void ls_ted_del(struct ls_ted *ted) +.. c:function:: void ls_connect_vertices(struct ls_vertex *src, struct ls_vertex *dst, struct ls_edge *edge) +.. c:function:: void ls_connect(struct ls_vertex *vertex, struct ls_edge *edge, bool source) +.. c:function:: void ls_disconnect(struct ls_vertex *vertex, struct ls_edge *edge, bool source) +.. c:function:: void ls_disconnect_edge(struct ls_edge *edge) + + +Link State Messages +------------------- + +This part of the API provides functions and data structure to ease the +communication between the *Producer* and *Consumer* daemons. + +Communications principles +^^^^^^^^^^^^^^^^^^^^^^^^^ + +Recent ZAPI Opaque Message is used to exchange Link State data between daemons. +For that purpose, Link State API provides new functions to serialize and parse +Link State information through the ZAPI Opaque message. A dedicated flag, +named ZAPI_OPAQUE_FLAG_UNICAST, allows daemons to send a unicast or a multicast +Opaque message and is used as follow for the Link State exchange: + +- Multicast: To send data update to all daemons that have subscribed to the + Link State Update message +- Unicast: To send initial Link State information from a particular daemon. All + data are send only to the daemon that request Link State Synchronisatio + +Figure 1 below, illustrates the ZAPI Opaque message exchange between a +*Producer* (an IGP like OSPF or IS-IS) and a *Consumer* (e.g. BGP). The +message sequences are as follows: + +- First, both *Producer* and *Consumer* must register to their respective ZAPI + Opaque Message. **Link State Sync** for the *Producer* in order to receive + Database synchronisation request from a *Consumer*. **Link State Update** for + the *Consumer* in order to received any Link State update from a *Producer*. + These register messages are stored by Zebra to determine to which daemon it + should redistribute the ZAPI messages it receives. +- Then, the *Consumer* sends a **Link State Synchronistation** request with the + Multicast method in order to receive the complete Link State Database from a + *Producer*. ZEBRA daemon forwards this message to any *Producer* daemons that + previously registered to this message. If no *Producer* has yet registered, + the request is lost. Thus, if the *Consumer* receives no response whithin a + given timer, it means that no *Producer* are available right now. So, the + *Consumer* must send the same request until it receives a Link State Database + Synchronistation message. This behaviour is necessary as we can't control in + which order daemons are started. It is up to the *Consumer* daemon to fix the + timeout and the number of retry. +- When a *Producer* receives a **Link State Synchronisation** request, it + starts sending all elements of its own Link State Database through the + **Link State Database Synchronisation** message. These messages are send with + the Unicast method to avoid flooding other daemons with these elements. ZEBRA + layer ensures to forward the message to the right daemon. +- When a *Producer* update its Link State Database, it automatically sends a + **Link State Update** message with the Multicast method. In turn, ZEBRA + daemon forwards the message to all *Consumer* daemons that previously + registered to this message. if no daemon is registered, the message is lost. +- A daemon could unregister from the ZAPI Opaque message registry at any time. + In this case, the ZEBRA daemon stops to forward any messages it receives to + this daemon, even if it was previously converns. + +:: + + IGP ZEBRA Consumer + (OSPF/IS-IS) (ZAPI Opaque Thread) (e.g. BGP) + | | | \ + | | Register LS Update | | + | |<----------------------------| Register Phase + | | | | + | | Request LS Sync | | + | |<----------------------------| | + : : : A | + | Register LS Sync | | | | + |----------------------------->| | | / + : : : |TimeOut + : : : | + | | | | + | | Request LS Sync | v \ + | Request LS Sync |<----------------------------| | + |<-----------------------------| | Synchronistation + | LS DB Sync | | Phase + |----------------------------->| LS DB Sync | | + | |---------------------------->| | + | LS DB Sync (cont'd) | | | + |----------------------------->| LS DB Sync (cont'd) | | + | . |---------------------------->| | + | . | . | | + | . | . | | + | LS DB Sync (end) | . | | + |----------------------------->| LS DB Sync (end) | | + | |---------------------------->| | + | | | / + : : : + : : : + | LS Update | | \ + |----------------------------->| LS Update | | + | |---------------------------->| Update Phase + | | | | + : : : / + : : : + | | | \ + | | Unregister LS Update | | + | |<----------------------------| Deregister Phase + | | | | + | LS Update | | | + |----------------------------->| | | + | | | / + | | | + + Figure 1: Link State messages exchange + + +Data Structures +^^^^^^^^^^^^^^^ + +The Link State Message is defined to convey Link State parameters from +the routing protocol (OSPF or IS-IS) to other daemons e.g. BGP. + +.. c:type:: struct ls_message + +The structure is composed of: + +- Event of the message: + + - Sync: Send the whole LS DB following a request + - Add: Send the a new Link State element + - Update: Send an update of an existing Link State element + - Delete: Indicate that the given Link State element is removed + +- Type of Link State element: Node, Attribute or Prefix +- Remote node id when known +- Data: Node, Attributes or Prefix + +A Link State Message can carry only one Link State Element (Node, Attributes +of Prefix) at once, and only one Link State Message is sent through ZAPI +Opaque Link State type at once. + +Functions +^^^^^^^^^ + +.. c:function:: struct ls_message *ls_parse_msg(struct stream *s) +.. c:function:: int ls_send_msg(struct zclient *zclient, struct ls_message *msg, struct zapi_opaque_reg_info *dst) +.. c:function:: struct ls_message *ls_vertex2msg(struct ls_message *msg, struct ls_vertex *vertex) +.. c:function:: struct ls_message *ls_edge2msg(struct ls_message *msg, struct ls_edge *edge) +.. c:function:: struct ls_message *ls_subnet2msg(struct ls_message *msg, struct ls_subnet *subnet) +.. c:function:: int ls_sync_ted(struct ls_ted *ted, struct zclient *zclient, struct zapi_opaque_reg_info *dst) + diff --git a/doc/developer/logging.rst b/doc/developer/logging.rst index 2f2444373c..cf3aa8d17f 100644 --- a/doc/developer/logging.rst +++ b/doc/developer/logging.rst @@ -83,7 +83,7 @@ Extensions +-----------+--------------------------+----------------------------------------------+ | ``%pNHs`` | ``struct nexthop *`` | ``1.2.3.4 if 15`` | +-----------+--------------------------+----------------------------------------------+ -| ``%pFX`` + ``struct bgp_dest *`` | ``fe80::1234/64`` available in BGP only | +| ``%pFX`` | ``struct bgp_dest *`` | ``fe80::1234/64`` (available in BGP only) | +-----------+--------------------------+----------------------------------------------+ Printf features like field lengths can be used normally with these extensions, diff --git a/doc/developer/lua.rst b/doc/developer/lua.rst deleted file mode 100644 index 3315c31ad7..0000000000 --- a/doc/developer/lua.rst +++ /dev/null @@ -1,65 +0,0 @@ -.. _lua: - -Lua -=== - -Lua is currently experimental within FRR and has very limited -support. If you would like to compile FRR with Lua you must -follow these steps: - -1. Installation of Relevant Libraries - - .. code-block:: shell - - apt-get install lua5.3 liblua5-3 liblua5.3-dev - - These are the Debian libraries that are needed. There should - be equivalent RPM's that can be found - -2. Compilation - - Configure needs these options - - .. code-block:: shell - - ./configure --enable-dev-build --enable-lua <all other interesting options> - - Typically you just include the two new enable lines to build with it. - -3. Using Lua - - * Copy tools/lua.scr into /etc/frr - - * Create a route-map match command - - .. code-block:: console - - ! - router bgp 55 - neighbor 10.50.11.116 remote-as external - address-family ipv4 unicast - neighbor 10.50.11.116 route-map TEST in - exit-address-family - ! - route-map TEST permit 10 - match command mooey - ! - - * In the lua.scr file make sure that you have a function named 'mooey' - - .. code-block:: console - - function mooey () - zlog_debug(string.format("afi: %d: %s %d ifdx: %d aspath: %s localpref: %d", - prefix.family, prefix.route, nexthop.metric, - nexthop.ifindex, nexthop.aspath, nexthop.localpref)) - - nexthop.metric = 33 - nexthop.localpref = 13 - return 3 - end - -4. General Comments - - Please be aware that this is extremely experimental and needs a ton of work - to get this up into a state that is usable. diff --git a/doc/developer/ospf-sr.rst b/doc/developer/ospf-sr.rst index efe9b1b12f..263db9dfb9 100644 --- a/doc/developer/ospf-sr.rst +++ b/doc/developer/ospf-sr.rst @@ -17,6 +17,7 @@ Supported Features * Automatic provisioning of MPLS table * Equal Cost Multi-Path (ECMP) * Static route configuration with label stack up to 32 labels +* TI-LFA (for P2P interfaces only) Interoperability ---------------- @@ -182,6 +183,71 @@ called. Once check the validity of labels, they are send to ZEBRA layer through command for deletion. This is completed by a new labelled route through `ZEBRA_ROUTE_ADD` command, respectively `ZEBRA_ROUTE_DELETE` command. +TI-LFA +^^^^^^ + +Experimental support for Topology Independent LFA (Loop-Free Alternate), see +for example 'draft-bashandy-rtgwg-segment-routing-ti-lfa-05'. The related +files are `ospf_ti_lfa.c/h`. + +The current implementation is rather naive and does not support the advanced +optimizations suggested in e.g. RFC7490 or RFC8102. It focuses on providing +the essential infrastructure which can also later be used to enhance the +algorithmic aspects. + +Supported features: + +* Link and node protection +* Intra-area support +* Proper use of Prefix- and Adjacency-SIDs in label stacks +* Asymmetric weights (using reverse SPF) +* Non-adjacent P/Q spaces +* Protection of Prefix-SIDs + +If configured for every SPF run the routing table is enriched with additional +backup paths for every prefix. The corresponding Prefix-SIDs are updated with +backup paths too within the OSPF SR update task. + +Informal High-Level Algorithm Description: + +:: + + p_spaces = empty_list() + + for every protected_resource (link or node): + p_space = generate_p_space(protected_resource) + p_space.q_spaces = empty_list() + + for every destination that is affected by the protected_resource: + q_space = generate_q_space(destination) + + # The label stack is stored in q_space + generate_label_stack(p_space, q_space) + + # The p_space collects all its q_spaces + p_spaces.q_spaces.add(q_space) + + p_spaces.add(p_space) + + adjust_routing_table(p_spaces) + +Possible Performance Improvements: + +* Improve overall datastructures, get away from linked lists for vertices +* Don't calculate a Q space for every destination, but for a minimum set of + backup paths that cover all destinations in the post-convergence SPF. The + thinking here is that once a backup path is known that it is also a backup + path for all nodes on the path themselves. This can be done by using the + leafs of a trimmed minimum spanning tree generated out of the post- + convergence SPF tree for that particular P space. +* For an alternative (maybe better) optimization look at + https://tools.ietf.org/html/rfc7490#section-5.2.1.3 which describes using + the Q space of the node which is affected by e.g. a link failure. Note that + this optimization is topology dependent. + +It is highly recommended to read e.g. `Segment Routing I/II` by Filsfils to +understand the basics of Ti-LFA. + Configuration ------------- diff --git a/doc/developer/path-internals-daemon.rst b/doc/developer/path-internals-daemon.rst new file mode 100644 index 0000000000..29f017284f --- /dev/null +++ b/doc/developer/path-internals-daemon.rst @@ -0,0 +1,115 @@ +PATHD Internals +=============== + +Architecture +------------ + +Overview +........ + +The pathd deamon manages the segment routing policies, it owns the data +structures representing them and can load modules that manipulate them like the +PCEP module. Its responsibility is to select a candidate path for each +configured policy and to install it into Zebra. + +Zebra +..... + +Zebra manages policies that are active or pending to be activated due to the +next hop not being available yet. In zebra, policy data structures and APIs are +defined in `zebra_srte.[hc]`. + +The responsibilities of Zebra are: + + - Store the policies' segment list. + - Install the policies when their next-hop is available. + - Notify other daemons of the status of the policies. + +Adding and removing policies is done using the commands `ZEBRA_SR_POLICY_SET` +and `ZEBRA_SR_POLICY_DELETE` as parameter of the function `zebra_send_sr_policy` +all defined in `zclient.[hc]`. + +If the first segment of the policy is an unknown label, it is kept until +notified by the mpls hooks `zebra_mpls_label_created`, and then it is installed. + +To get notified when a policy status changes, a client can implement the +`sr_policy_notify_status` callback defined in `zclient.[hc]`. + +For encoding/decoding the various data structures used to comunicate with zebra, +the following functions are available from `zclient.[hc]`: +`zapi_sr_policy_encode`, `zapi_sr_policy_decode` and +`zapi_sr_policy_notify_status_decode`. + + +Pathd +..... + + +The pathd daemon manages all the possible candidate paths for the segment +routing policies and selects the best one following the +`segment routing policy draft <https://tools.ietf.org/html/draft-ietf-spring-segment-routing-policy-06#section-2.9>`_. +It also supports loadable modules for handling dynamic candidate paths and the +creation of new policies and candidate paths at runtime. + +The responsibilities of the pathd base daemon, not including any optional +modules, are: + + - Store the policies and all the possible candidate paths for them. + - Select the best candidate path for each policy and send it to Zebra. + - Provide VTYSH configuration to set up policies and candidate paths. + - Provide a Northbound API to manipulate **configured** policies and candidate paths. + - Handle loadable modules for extending the functionality. + - Provide an API to the loadable module to manipulate policies and candidate paths. + + +Threading Model +--------------- + +The daemon runs completely inside the main thread using FRR event model, there +is no threading involved. + + +Source Code +----------- + +Internal Data Structures +........................ + +The main data structures for policies and candidate paths are defined in +`pathd.h` and implemented in `pathd.c`. + +When modifying these structures, either directly or through the functions +exported by `pathd.h`, nothing should be deleted/freed right away. The deletion +or modification flags must be set and when all the changes are done, the +function `srte_apply_changes` must be called. When called, a new candidate path +may be elected and sent to Zebra, and all the structures flagged as deleted +will be freed. In addition, a hook will be called so dynamic modules can perform +any required action when the elected candidate path changes. + + +Northbound API +.............. + +The northbound API is defined in `path_nb.[ch]` and implemented in +`path_nb_config.c` for configuration data and `path_nb_state.c` for operational +data. + + +Command Line Client +................... + +The command-line client (VTYSH) is implemented in `path_cli.c`. + + +Interface with Zebra +.................... + +All the functions interfacing with Zebra are defined and implemented in +`path_zebra.[hc]`. + + +Loadable Module API +................... + +For the time being, the API the loadable module uses is defined by `pathd.h`, +but in the future, it should be moved to a dedicated include file. diff --git a/doc/developer/path-internals-pcep.rst b/doc/developer/path-internals-pcep.rst new file mode 100644 index 0000000000..ca318314f1 --- /dev/null +++ b/doc/developer/path-internals-pcep.rst @@ -0,0 +1,193 @@ +PCEP Module Internals +===================== + +Introduction +------------ + +The PCEP module for the pathd daemon implements the PCEP protocol described in +:rfc:`5440` to update the policies and candidate paths. + +The protocol encoding/decoding and the basic session management is handled by +the `pceplib external library 1.2 <https://github.com/volta-networks/pceplib/tree/devel-1.2>`_. + +Together with pceplib, this module supports at least partially: + + - :rfc:`5440` + + Most of the protocol defined in the RFC is implemented. + All the messages can be parsed, but this was only tested in the context + of segment routing. Only a very small subset of metric types can be + configured, and there is a known issue with some Cisco routers not + following the IANA numbers for metrics. + + - :rfc:`8231` + + Support delegation of candidate path after performing the initial + computation request. If the PCE does not respond or cannot compute + a path, an empty candidate path is delegated to the PCE. + Only tested in the context of segment routing. + + - :rfc:`8408` + + Only used to comunicate the support for segment routing to the PCE. + + - :rfc:`8664` + + All the NAI types are implemented, but only the MPLS NAI are supported. + If the PCE provide segments that are not MPLS labels, the PCC will + return an error. + +Note that pceplib supports more RFCs and drafts, see pceplib +`README <https://github.com/volta-networks/pceplib/blob/master/README.md>`_ +for more details. + + +Architecture +------------ + +Overview +........ + +The module is separated into multiple layers: + + - pathd interface + - command-line console + - controller + - PCC + - pceplib interface + +The pathd interface handles all the interactions with the daemon API. + +The command-line console handles all the VTYSH configuration commands. + +The controller manages the multiple PCC connections and the interaction between +them and the daemon interface. + +The PCC handles a single connection to a PCE through a pceplib session. + +The pceplib interface abstracts the API of the pceplib. + +.. figure:: ../figures/pcep_module_threading_overview.svg + + +Threading Model +--------------- + +The module requires multiple threads to cooperate: + + - The main thread used by the pathd daemon. + - The controller pthread used to isolate the PCC from the main thread. + - The possible threads started in the pceplib library. + +To ensure thread safety, all the controller and PCC state data structures can +only be read and modified in the controller thread, and all the global data +structures can only be read and modified in the main thread. Most of the +interactions between these threads are done through FRR timers and events. + +The controller is the bridge between the two threads, all the functions that +**MUST** be called from the main thread start with the prefix `pcep_ctrl_` and +all the functions that **MUST** be called from the controller thread start +with the prefix `pcep_thread_`. When an asynchronous action must be taken in +a different thread, an FRR event is sent to the thread. If some synchronous +operation is needed, the calling thread will block and run a callback in the +other thread, there the result is **COPIED** and returned to the calling thread. + +No function other than the controller functions defined for it should be called +from the main thread. The only exception being some utility functions from +`path_pcep_lib.[hc]`. + +All the calls to pathd API functions **MUST** be performed in the main thread, +for that, the controller sends FRR events handled in function +`path_pcep.c:pcep_main_event_handler`. + +For the same reason, the console client only runs in the main thread. It can +freely use the global variable, but **MUST** use controller's `pcep_ctrl_` +functions to interact with the PCCs. + + +Source Code +----------- + +Generic Data Structures +....................... + +The data structures are defined in multiple places, and where they are defined +dictates where they can be used. + +The data structures defined in `path_pcep.h` can be used anywhere in the module. + +Internally, throughout the module, the `struct path` data structure is used +to describe PCEP messages. It is a simplified flattened structure that can +represent multiple complex PCEP message types. The conversion from this +structure to the PCEP data structures used by pceplib is done in the pceplib +interface layer. + +The data structures defined in `path_pcep_controller.h` should only be used +in `path_pcep_controller.c`. Even if a structure pointer is passed as a parameter +to functions defined in `path_pcep_pcc.h`, these should consider it as an opaque +data structure only used to call back controller functions. + +The same applies to the structures defined in `path_pcep_pcc.h`, even if the +controller owns a reference to this data structure, it should never read or +modify it directly, it should be considered an opaque structure. + +The global data structure can be accessed from the pathd interface layer +`path_pcep.c` and the command line client code `path_pcep_cli.c`. + + +Interface With Pathd +.................... + +All the functions calling or called by the pathd daemon are implemented in +`path_pcep.c`. These functions **MUST** run in the main FRR thread, and +all the interactions with the controller and the PCCs **MUST** pass through +the controller's `pcep_ctrl_` prefixed functions. + +To handle asynchronous events from the PCCs, a callback is passed to +`pcep_ctrl_initialize` that is called in the FRR main thread context. + + +Command Line Client +................... + +All the command line configuration commands (VTYSH) are implemented in +`path_pcep_cli.c`. All the functions there run in the main FRR thread and +can freely access the global variables. All the interaction with the +controller's and the PCCs **MUST** pass through the controller `pcep_ctrl_` +prefixed functions. + + +Debugging Helpers +................. + +All the functions formating data structures for debugging and logging purposes +are implemented in `path_pcep_debug.[hc]`. + + +Interface with pceplib +...................... + +All the functions calling the pceplib external library are defined in +`path_pcep_lib.[hc]`. Some functions are called from the main FRR thread, like +`pcep_lib_initialize`, `pcep_lib_finalize`; some can be called from either +thread, like `pcep_lib_free_counters`; some function must be called from the +controller thread, like `pcep_lib_connect`. This will probably be formalized +later on with function prefix like done in the controller. + + +Controller +.......... + +The controller is defined and implemented in `path_pcep_controller.[hc]`. +Part of the controller code runs in FRR main thread and part runs in its own +FRR pthread started to isolate the main thread from the PCCs' event loop. +To communicate between the threads it uses FRR events, timers and +`thread_execute` calls. + + +PCC +... + +Each PCC instance owns its state and runs in the controller thread. They are +defined and implemented in `path_pcep_pcc.[hc]`. All the interactions with +the daemon must pass through some controller's `pcep_thread_` prefixed function. diff --git a/doc/developer/path-internals.rst b/doc/developer/path-internals.rst new file mode 100644 index 0000000000..2c2df0f378 --- /dev/null +++ b/doc/developer/path-internals.rst @@ -0,0 +1,11 @@ +.. _path_internals: + +********* +Internals +********* + +.. toctree:: + :maxdepth: 2 + + path-internals-daemon + path-internals-pcep diff --git a/doc/developer/path.rst b/doc/developer/path.rst new file mode 100644 index 0000000000..b6d2438c58 --- /dev/null +++ b/doc/developer/path.rst @@ -0,0 +1,11 @@ +.. _path: + +***** +PATHD +***** + +.. toctree:: + :maxdepth: 2 + + path-internals + diff --git a/doc/developer/scripting.rst b/doc/developer/scripting.rst new file mode 100644 index 0000000000..b0413619ab --- /dev/null +++ b/doc/developer/scripting.rst @@ -0,0 +1,433 @@ +.. _scripting: + +Scripting +========= + +.. seealso:: User docs for scripting + +Overview +-------- + +FRR has the ability to call Lua scripts to perform calculations, make +decisions, or otherwise extend builtin behavior with arbitrary user code. This +is implemented using the standard Lua C bindings. The supported version of Lua +is 5.3. + +C objects may be passed into Lua and Lua objects may be retrieved by C code via +a marshalling system. In this way, arbitrary data from FRR may be passed to +scripts. It is possible to pass C functions as well. + +The Lua environment is isolated from the C environment; user scripts cannot +access FRR's address space unless explicitly allowed by FRR. + +For general information on how Lua is used to extend C, refer to Part IV of +"Programming in Lua". + +https://www.lua.org/pil/contents.html#24 + + +Design +------ + +Why Lua +^^^^^^^ + +Lua is designed to be embedded in C applications. It is very small; the +standard library is 220K. It is relatively fast. It has a simple, minimal +syntax that is relatively easy to learn and can be understood by someone with +little to no programming experience. Moreover it is widely used to add +scripting capabilities to applications. In short it is designed for this task. + +Reasons against supporting multiple scripting languages: + +- Each language would require different FFI methods, and specifically + different object encoders; a lot of code +- Languages have different capabilities that would have to be brought to + parity with each other; a lot of work +- Languages have vastly different performance characteristics; this would + create alot of basically unfixable issues, and result in a single de facto + standard scripting language (the fastest) +- Each language would need a dedicated maintainer for the above reasons; + this is pragmatically difficult +- Supporting multiple languages fractures the community and limits the audience + with which a given script can be shared + +General +^^^^^^^ + +FRR's concept of a script is somewhat abstracted away from the fact that it is +Lua underneath. A script in has two things: + +- name +- state + +In code: + +.. code-block:: c + + struct frrscript { + /* Script name */ + char *name; + + /* Lua state */ + struct lua_State *L; + }; + + +``name`` is simply a string. Everything else is in ``state``, which is itself a +Lua library object (``lua_State``). This is an opaque struct that is +manipulated using ``lua_*`` functions. The basic ones are imported from +``lua.h`` and the rest are implemented within FRR to fill our use cases. The +thing to remember is that all operations beyond the initial loading the script +take place on this opaque state object. + +There are four basic actions that can be done on a script: + +- load +- execute +- query state +- unload + +They are typically done in this order. + + +Loading +^^^^^^^ + +A snippet of Lua code is referred to as a "chunk". These are simply text. FRR +presently assumes chunks are located in individual files specific to one task. +These files are stored in the scripts directory and must end in ``.lua``. + +A script object is created by loading a script. This is done with +``frrscript_load()``. This function takes the name of the script and an +optional callback function. The string ".lua" is appended to the script name, +and the resultant filename is looked for in the scripts directory. + +For example, to load ``/etc/frr/scripts/bingus.lua``: + +.. code-block:: c + + struct frrscript *fs = frrscript_load("bingus", NULL); + +During loading the script is validated for syntax and its initial environment +is setup. By default this does not include the Lua standard library; there are +security issues to consider, though for practical purposes untrusted users +should not be able to write the scripts directory anyway. If desired the Lua +standard library may be added to the script environment using +``luaL_openlibs(fs->L)`` after loading the script. Further information on +setting up the script environment is in the Lua manual. + + +Executing +^^^^^^^^^ + +After loading, scripts may be executed. A script may take input in the form of +variable bindings set in its environment prior to being run, and may provide +results by setting the value of variables. Arbitrary C values may be +transferred into the script environment, including functions. + +A typical execution call looks something like this: + +.. code-block:: c + + struct frrscript *fs = frrscript_load(...); + + int status_ok = 0, status_fail = 1; + struct prefix p = ...; + + struct frrscript_env env[] = { + {"integer", "STATUS_FAIL", &status_fail}, + {"integer", "STATUS_OK", &status_ok}, + {"prefix", "myprefix", &p}, + {}}; + + int result = frrscript_call(fs, env); + + +To execute a loaded script, we need to define the inputs. These inputs are +passed by binding values to variable names that will be accessible within the +Lua environment. Basically, all communication with the script takes place via +global variables within the script, and to provide inputs we predefine globals +before the script runs. This is done by passing ``frrscript_call()`` an array +of ``struct frrscript_env``. Each struct has three fields. The first identifies +the type of the value being passed; more on this later. The second defines the +name of the global variable within the script environment to bind the third +argument (the value) to. + +The script is then executed and returns a general status code. In the success +case this will be 0, otherwise it will be nonzero. The script itself does not +determine this code, it is provided by the Lua interpreter. + + +Querying State +^^^^^^^^^^^^^^ + +When a chunk is executed, its state at exit is preserved and can be inspected. + +After running a script, results may be retrieved by querying the script's +state. Again this is done by retrieving the values of global variables, which +are known to the script author to be "output" variables. + +A result is retrieved like so: + +.. code-block:: c + + struct frrscript_env myresult = {"string", "myresult"}; + + char *myresult = frrscript_get_result(fs, &myresult); + + ... do something ... + + XFREE(MTYPE_TMP, myresult); + + +As with arguments, results are retrieved by providing a ``struct +frrscript_env`` specifying a type and a global name. No value is necessary, nor +is it modified by ``frrscript_get_result()``. That function simply extracts the +requested value from the script state and returns it. + +In most cases the returned value will be allocated with ``MTYPE_TMP`` and will +need to be freed after use. + + +Unloading +^^^^^^^^^ + +To destroy a script and its associated state: + +.. code-block:: c + + frrscript_unload(fs); + +Values returned by ``frrscript_get_result`` are still valid after the script +they were retrieved from is unloaded. + +Note that you must unload and then load the script if you want to reset its +state, for example to run it again with different inputs. Otherwise the state +from the previous run carries over into subsequent runs. + + +.. _marshalling: + +Marshalling +^^^^^^^^^^^ + +Earlier sections glossed over the meaning of the type name field in ``struct +frrscript_env`` and how data is passed between C and Lua. Lua, as a dynamically +typed, garbage collected language, cannot directly use C values without some +kind of marshalling / unmarshalling system to translate types between the two +runtimes. + +Lua communicates with C code using a stack. C code wishing to provide data to +Lua scripts must provide a function that marshalls the C data into a Lua +representation and pushes it on the stack. C code wishing to retrieve data from +Lua must provide a corresponding unmarshalling function that retrieves a Lua +value from the stack and converts it to the corresponding C type. These two +functions, together with a chosen name of the type they operate on, are +referred to as ``codecs`` in FRR. + +A codec is defined as: + +.. code-block:: c + + typedef void (*encoder_func)(lua_State *, const void *); + typedef void *(*decoder_func)(lua_State *, int); + + struct frrscript_codec { + const char *typename; + encoder_func encoder; + decoder_func decoder; + }; + +A typename string and two function pointers. + +``typename`` can be anything you want. For example, for the combined types of +``struct prefix`` and its equivalent in Lua I have chosen the name ``prefix``. +There is no restriction on naming here, it is just a human name used as a key +and specified when passing and retrieving values. + +``encoder`` is a function that takes a ``lua_State *`` and a C type and pushes +onto the Lua stack a value representing the C type. For C structs, the usual +case, this will typically be a Lua table (tables are the only datastructure Lua +has). For example, here is the encoder function for ``struct prefix``: + + +.. code-block:: c + + void lua_pushprefix(lua_State *L, const struct prefix *prefix) + { + char buffer[PREFIX_STRLEN]; + + zlog_debug("frrlua: pushing prefix table"); + + lua_newtable(L); + lua_pushstring(L, prefix2str(prefix, buffer, PREFIX_STRLEN)); + lua_setfield(L, -2, "network"); + lua_pushinteger(L, prefix->prefixlen); + lua_setfield(L, -2, "length"); + lua_pushinteger(L, prefix->family); + lua_setfield(L, -2, "family"); + } + +This function pushes a single value onto the Lua stack. It is a table whose equivalent in Lua is: + +.. code-block:: + + { ["network"] = "1.2.3.4/24", ["prefixlen"] = 24, ["family"] = 2 } + + +``decoder`` does the reverse; it takes a ``lua_State *`` and an index into the +stack, and unmarshalls a Lua value there into the corresponding C type. Again +for ``struct prefix``: + + +.. code-block:: c + + void *lua_toprefix(lua_State *L, int idx) + { + struct prefix *p = XCALLOC(MTYPE_TMP, sizeof(struct prefix)); + + lua_getfield(L, idx, "network"); + str2prefix(lua_tostring(L, -1), p); + lua_pop(L, 1); + + return p; + } + +By convention these functions should be called ``lua_to*``, as this is the +naming convention used by the Lua C library for the basic types e.g. +``lua_tointeger`` and ``lua_tostring``. + +The returned data must always be copied off the stack and the copy must be +allocated with ``MTYPE_TMP``. This way it is possible to unload the script +(destroy the state) without invalidating any references to values stored in it. + +To register a new type with its corresponding encoding functions: + +.. code-block:: c + + struct frrscript_codec frrscript_codecs_lib[] = { + {.typename = "prefix", + .encoder = (encoder_func)lua_pushprefix, + .decoder = lua_toprefix}, + {.typename = "sockunion", + .encoder = (encoder_func)lua_pushsockunion, + .decoder = lua_tosockunion}, + ... + {}}; + + frrscript_register_type_codecs(frrscript_codecs_lib); + +From this point on the type names are available to be used when calling any +script and getting its results. + +.. note:: + + Marshalled types are not restricted to simple values like integers, strings + and tables. It is possible to marshall a type such that the resultant object + in Lua is an actual object-oriented object, complete with methods that call + back into defined C functions. See the Lua manual for how to do this; for a + code example, look at how zlog is exported into the script environment. + + +Script Environment +------------------ + +Logging +^^^^^^^ + +For convenience, script environments are populated by default with a ``log`` +object which contains methods corresponding to each of the ``zlog`` levels: + +.. code-block:: lua + + log.info("info") + log.warn("warn") + log.error("error") + log.notice("notice") + log.debug("debug") + +The log messages will show up in the daemon's log output. + + +Examples +-------- + +For a complete code example involving passing custom types, retrieving results, +and doing complex calculations in Lua, look at the implementation of the +``match script SCRIPT`` command for BGP routemaps. This example calls into a +script with a route prefix and attributes received from a peer and expects the +script to return a match / no match / match and update result. + +An example script to use with this follows. This script matches, does not match +or updates a route depending on how many BGP UPDATE messages the peer has +received when the script is called, simply as a demonstration of what can be +accomplished with scripting. + +.. code-block:: lua + + + -- Example route map matching + -- author: qlyoung + -- + -- The following variables are available to us: + -- log + -- logging library, with the usual functions + -- prefix + -- the route under consideration + -- attributes + -- the route's attributes + -- peer + -- the peer which received this route + -- RM_FAILURE + -- status code in case of failure + -- RM_NOMATCH + -- status code for no match + -- RM_MATCH + -- status code for match + -- RM_MATCH_AND_CHANGE + -- status code for match-and-set + -- + -- We need to set the following out values: + -- action + -- Set to the appropriate status code to indicate what we did + -- attributes + -- Setting fields on here will propagate them back up to the caller if + -- 'action' is set to RM_MATCH_AND_CHANGE. + + + log.info("Evaluating route " .. prefix.network .. " from peer " .. peer.remote_id.string) + + function on_match (prefix, attrs) + log.info("Match") + action = RM_MATCH + end + + function on_nomatch (prefix, attrs) + log.info("No match") + action = RM_NOMATCH + end + + function on_match_and_change (prefix, attrs) + action = RM_MATCH_AND_CHANGE + log.info("Match and change") + attrs["metric"] = attrs["metric"] + 7 + end + + special_routes = { + ["172.16.10.4/24"] = on_match, + ["172.16.13.1/8"] = on_nomatch, + ["192.168.0.24/8"] = on_match_and_change, + } + + + if special_routes[prefix.network] then + special_routes[prefix.network](prefix, attributes) + elseif peer.stats.update_in % 3 == 0 then + on_match(prefix, attributes) + elseif peer.stats.update_in % 2 == 0 then + on_nomatch(prefix, attributes) + else + on_match_and_change(prefix, attributes) + end + diff --git a/doc/developer/subdir.am b/doc/developer/subdir.am index 3c0d203007..f7e4486ef0 100644 --- a/doc/developer/subdir.am +++ b/doc/developer/subdir.am @@ -27,16 +27,17 @@ dev_RSTFILES = \ doc/developer/building.rst \ doc/developer/cli.rst \ doc/developer/conf.py \ + doc/developer/cross-compiling.rst \ doc/developer/frr-release-procedure.rst \ doc/developer/grpc.rst \ doc/developer/hooks.rst \ doc/developer/include-compile.rst \ doc/developer/index.rst \ doc/developer/library.rst \ + doc/developer/link-state.rst \ doc/developer/lists.rst \ doc/developer/locking.rst \ doc/developer/logging.rst \ - doc/developer/lua.rst \ doc/developer/memtypes.rst \ doc/developer/modules.rst \ doc/developer/next-hop-tracking.rst \ @@ -46,12 +47,19 @@ dev_RSTFILES = \ doc/developer/packaging-debian.rst \ doc/developer/packaging-redhat.rst \ doc/developer/packaging.rst \ + doc/developer/path-internals-daemon.rst \ + doc/developer/path-internals-pcep.rst \ + doc/developer/path-internals.rst \ + doc/developer/path.rst \ doc/developer/rcu.rst \ + doc/developer/scripting.rst \ doc/developer/static-linking.rst \ + doc/developer/tracing.rst \ doc/developer/testing.rst \ doc/developer/topotests-snippets.rst \ doc/developer/topotests.rst \ doc/developer/workflow.rst \ + doc/developer/xrefs.rst \ doc/developer/zebra.rst \ # end diff --git a/doc/developer/topotests-markers.rst b/doc/developer/topotests-markers.rst new file mode 100644 index 0000000000..9f92412595 --- /dev/null +++ b/doc/developer/topotests-markers.rst @@ -0,0 +1,114 @@ +.. _topotests-markers: + +Markers +-------- + +To allow for automated selective testing on large scale continuous integration +systems, all tests must be marked with at least one of the following markers: + +* babeld +* bfdd +* bgpd +* eigrpd +* isisd +* ldpd +* nhrpd +* ospf6d +* ospfd +* pathd +* pbrd +* pimd +* ripd +* ripngd +* sharpd +* staticd +* vrrpd + +The markers corespond to the daemon subdirectories in FRR's source code and have +to be added to tests on a module level depending on which daemons are used +during the test. + +The goal is to have continuous integration systems scan code submissions, detect +changes to files in a daemons subdirectory and select only tests using that +daemon to run to shorten developers waiting times for test results and save test +infrastructure resources. + +Newly written modules and code changes on tests, which do not contain any or +incorrect markers will be rejected by reviewers. + + +Registering markers +^^^^^^^^^^^^^^^^^^^ +The Registration of new markers takes place in the file +``tests/topotests/pytest.ini``: + +.. code:: python3 + + # tests/topotests/pytest.ini + [pytest] + ... + markers = + babeld: Tests that run against BABELD + bfdd: Tests that run against BFDD + ... + vrrpd: Tests that run against VRRPD + + +Adding markers to tests +^^^^^^^^^^^^^^^^^^^^^^^ +Markers are added to a test by placing a global variable in the test module. + +Adding a single marker: + +.. code:: python3 + + import pytest + ... + + # add after imports, before defining classes or functions: + pytestmark = pytest.mark.bfdd + + ... + + def test_using_bfdd(): + + +Adding multiple markers: + +.. code:: python3 + + import pytest + ... + + # add after imports, before defining classes or functions: + pytestmark = [ + pytest.mark.bgpd, + pytest.mark.ospfd, + pytest.mark.ospf6d + ] + + ... + + def test_using_bgpd_ospfd_ospf6d(): + + +Selecting marked modules for testing +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Selecting by a single marker: + +.. code:: bash + + pytest -v -m isisd + +Selecting by multiple markers: + +.. code:: bash + + pytest -v -m "isisd or ldpd or nhrpd" + + +Further Information +^^^^^^^^^^^^^^^^^^^ +The `online pytest documentation <https://docs.pytest.org/en/stable/example/markers.html>`_ +provides further information and usage examples for pytest markers. + diff --git a/doc/developer/topotests.rst b/doc/developer/topotests.rst index 5486fd826d..93d81548b2 100644 --- a/doc/developer/topotests.rst +++ b/doc/developer/topotests.rst @@ -21,8 +21,10 @@ Installing Mininet Infrastructure apt-get install mininet apt-get install python-pip apt-get install iproute + apt-get install iperf pip install ipaddr pip install "pytest<5" + pip install "scapy>=2.4.2" pip install exabgp==3.4.17 (Newer 4.0 version of exabgp is not yet supported) useradd -d /var/run/exabgp/ -s /bin/false exabgp @@ -49,6 +51,28 @@ Next, update security limits by changing :file:`/etc/security/limits.conf` to:: Reboot for options to take effect. +SNMP Utilities Installation +""""""""""""""""""""""""""" + +To run SNMP test you need to install SNMP utilities and MIBs. Unfortunately +there are some errors in the upstream MIBS which need to be patched up. The +following steps will get you there on Ubuntu 20.04. + +.. code:: shell + + apt install snmpd snmp + apt install snmp-mibs-downloader + download-mibs + wget http://www.iana.org/assignments/ianaippmmetricsregistry-mib/ianaippmmetricsregistry-mib -O /usr/share/snmp/mibs/iana/IANA-IPPM-METRICS-REGISTRY-MIB + wget http://pastebin.com/raw.php?i=p3QyuXzZ -O /usr/share/snmp/mibs/ietf/SNMPv2-PDU + wget http://pastebin.com/raw.php?i=gG7j8nyk -O /usr/share/snmp/mibs/ietf/IPATM-IPMC-MIB + edit /etc/snmp/snmp.conf to look like this + # As the snmp packages come without MIB files due to license reasons, loading + # of MIBs is disabled by default. If you added the MIBs you can reenable + # loading them by commenting out the following line. + mibs +ALL + + FRR Installation ^^^^^^^^^^^^^^^^ @@ -84,6 +108,7 @@ If you prefer to manually build FRR, then use the following suggested config: --enable-user=frr \ --enable-group=frr \ --enable-vty-group=frrvty \ + --enable-snmp=agentx \ --with-pkg-extra-version=-my-manual-build And create ``frr`` user and ``frrvty`` group as follows: @@ -769,6 +794,8 @@ Requirements: conforms with this, run it without the :option:`-s` parameter. - Use `black <https://github.com/psf/black>`_ code formatter before creating a pull request. This ensures we have a unified code style. +- Mark test modules with pytest markers depending on the daemons used during the + tests (s. Markers) Tips: @@ -927,6 +954,8 @@ does what you need. If nothing is similar, then you may create a new topology, preferably, using the newest template (:file:`tests/topotests/example-test/test_template.py`). +.. include:: topotests-markers.rst + .. include:: topotests-snippets.rst License diff --git a/doc/developer/tracing.rst b/doc/developer/tracing.rst index ee0a6be008..c194ae1270 100644 --- a/doc/developer/tracing.rst +++ b/doc/developer/tracing.rst @@ -57,7 +57,7 @@ run the target in non-forking mode (no ``-d``) and use LTTng as usual (refer to LTTng user manual). When using USDT probes with LTTng, follow the example in `this article <https://lttng.org/blog/2019/10/15/new-dynamic-user-space-tracing-in-lttng/>`_. -To trace with dtrace or SystemTap, compile with :option:`--enable-usdt=yes` and +To trace with dtrace or SystemTap, compile with `--enable-usdt=yes` and use your tracer as usual. To see available USDT probes:: @@ -308,6 +308,31 @@ Limitations Tracers do not like ``fork()`` or ``dlopen()``. LTTng has some workarounds for this involving interceptor libraries using ``LD_PRELOAD``. +If you're running FRR in a typical daemonizing way (``-d`` to the daemons) +you'll need to run the daemons like so: + +.. code-block:: shell + + LD_PRELOAD=liblttng-ust-fork.so <daemon> + + +If you're using systemd this you can accomplish this for all daemons by +modifying ``frr.service`` like so: + +.. code-block:: diff + + --- a/frr.service + +++ b/frr.service + @@ -7,6 +7,7 @@ Before=network.target + OnFailure=heartbeat-failed@%n.service + + [Service] + +Environment="LD_PRELOAD=liblttng-ust-fork.so" + Nice=-5 + Type=forking + NotifyAccess=all + + USDT tracepoints are relatively high overhead and probably shouldn't be used for "flight recorder" functionality, i.e. enabling and passively recording all events for monitoring purposes. It's generally okay to use LTTng like this, diff --git a/doc/developer/workflow.rst b/doc/developer/workflow.rst index 4183ac6480..861d87b998 100644 --- a/doc/developer/workflow.rst +++ b/doc/developer/workflow.rst @@ -1262,6 +1262,9 @@ When documented this way, CLI commands can be cross referenced with the This is very helpful for users who want to quickly remind themselves what a particular command does. +When documenting a cli that has a ``no`` form, please do not include +the ``no`` in the ``.. index::`` line. + Configuration Snippets ^^^^^^^^^^^^^^^^^^^^^^ diff --git a/doc/developer/xrefs.rst b/doc/developer/xrefs.rst new file mode 100644 index 0000000000..6a0794d41b --- /dev/null +++ b/doc/developer/xrefs.rst @@ -0,0 +1,170 @@ +.. _xrefs: + +Introspection (xrefs) +===================== + +The FRR library provides an introspection facility called "xrefs." The intent +is to provide structured access to annotated entities in the compiled binary, +such as log messages and thread scheduling calls. + +Enabling and use +---------------- + +Support for emitting an xref is included in the macros for the specific +entities, e.g. :c:func:`zlog_info` contains the relevant statements. The only +requirement for the system to work is a GNU compatible linker that supports +section start/end symbols. (The only known linker on any system FRR supports +that does not do this is the Solaris linker.) + +To verify xrefs have been included in a binary or dynamic library, run +``readelf -n binary``. For individual object files, it's +``readelf -S object.o | grep xref_array`` instead. + +An extraction tool will be added in a future commit. + +Structure and contents +---------------------- + +As a slight improvement to security and fault detection, xrefs are divided into +a ``const struct xref *`` and an optional ``struct xrefdata *``. The required +const part contains: + +.. c:member:: enum xref_type xref.type + + Identifies what kind of object the xref points to. + +.. c:member:: int line +.. c:member:: const char *xref.file +.. c:member:: const char *xref.func + + Source code location of the xref. ``func`` will be ``<global>`` for + xrefs outside of a function. + +.. c:member:: struct xrefdata *xref.xrefdata + + The optional writable part of the xref. NULL if no non-const part exists. + +The optional non-const part has: + +.. c:member:: const struct xref *xrefdata.xref + + Pointer back to the constant part. Since circular pointers are close to + impossible to emit from inside a function body's static variables, this + is initialized at startup. + +.. c:member:: char xrefdata.uid[16] + + Unique identifier, see below. + +.. c:member:: const char *xrefdata.hashstr +.. c:member:: uint32_t xrefdata.hashu32[2] + + Input to unique identifier calculation. These should encompass all + details needed to make an xref unique. If more than one string should + be considered, use string concatenation for the initializer. + +Both structures can be extended by embedding them in a larger type-specific +struct, e.g. ``struct xref_logmsg *``. + +Unique identifiers +------------------ + +All xrefs that have a writable ``struct xrefdata *`` part are assigned an +unique identifier, which is formed as base32 (crockford) SHA256 on: + +- the source filename +- the ``hashstr`` field +- the ``hashu32`` fields + +.. note:: + + Function names and line numbers are intentionally not included to allow + moving items within a file without affecting the identifier. + +For running executables, this hash is calculated once at startup. When +directly reading from an ELF file with external tooling, the value must be +calculated when necessary. + +The identifiers have the form ``AXXXX-XXXXX`` where ``X`` is +``0-9, A-Z except I,L,O,U`` and ``A`` is ``G-Z except I,L,O,U`` (i.e. the +identifiers always start with a letter.) When reading identifiers from user +input, ``I`` and ``L`` should be replaced with ``1`` and ``O`` should be +replaced with ``0``. There are 49 bits of entropy in this identifier. + +Underlying machinery +-------------------- + +Xrefs are nothing other than global variables with some extra glue to make +them possible to find from the outside by looking at the binary. The first +non-obvious part is that they can occur inside of functions, since they're +defined as ``static``. They don't have a visible name -- they don't need one. + +To make finding these variables possible, another global variable, a pointer +to the first one, is created in the same way. However, it is put in a special +ELF section through ``__attribute__((section("xref_array")))``. This is the +section you can see with readelf. + +Finally, on the level of a whole executable or library, the linker will stuff +the individual pointers consecutive to each other since they're in the same +section — hence the array. Start and end of this array is given by the +linker-autogenerated ``__start_xref_array`` and ``__stop_xref_array`` symbols. +Using these, both a constructor to run at startup as well as an ELF note are +created. + +The ELF note is the entrypoint for externally retrieving xrefs from a binary +without having to run it. It can be found by walking through the ELF data +structures even if the binary has been fully stripped of debug and section +information. SystemTap's SDT probes & LTTng's trace points work in the same +way (though they emit 1 note for each probe, while xrefs only emit one note +in total which refers to the array.) Using xrefs does not impact SystemTap +or LTTng, the notes have identifiers they can be distinguished by. + +The ELF structure of a linked binary (library or executable) will look like +this:: + + $ readelf --wide -l -n lib/.libs/libfrr.so + + Elf file type is DYN (Shared object file) + Entry point 0x67d21 + There are 12 program headers, starting at offset 64 + + Program Headers: + Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align + PHDR 0x000040 0x0000000000000040 0x0000000000000040 0x0002a0 0x0002a0 R 0x8 + INTERP 0x125560 0x0000000000125560 0x0000000000125560 0x00001c 0x00001c R 0x10 + [Requesting program interpreter: /lib64/ld-linux-x86-64.so.2] + LOAD 0x000000 0x0000000000000000 0x0000000000000000 0x02aff0 0x02aff0 R 0x1000 + LOAD 0x02b000 0x000000000002b000 0x000000000002b000 0x0b2889 0x0b2889 R E 0x1000 + LOAD 0x0de000 0x00000000000de000 0x00000000000de000 0x070048 0x070048 R 0x1000 + LOAD 0x14e428 0x000000000014f428 0x000000000014f428 0x00fb70 0x01a2b8 RW 0x1000 + DYNAMIC 0x157a40 0x0000000000158a40 0x0000000000158a40 0x000270 0x000270 RW 0x8 + NOTE 0x0002e0 0x00000000000002e0 0x00000000000002e0 0x00004c 0x00004c R 0x4 + TLS 0x14e428 0x000000000014f428 0x000000000014f428 0x000000 0x000008 R 0x8 + GNU_EH_FRAME 0x12557c 0x000000000012557c 0x000000000012557c 0x00819c 0x00819c R 0x4 + GNU_STACK 0x000000 0x0000000000000000 0x0000000000000000 0x000000 0x000000 RW 0x10 + GNU_RELRO 0x14e428 0x000000000014f428 0x000000000014f428 0x009bd8 0x009bd8 R 0x1 + + (...) + + Displaying notes found in: .note.gnu.build-id + Owner Data size Description + GNU 0x00000014 NT_GNU_BUILD_ID (unique build ID bitstring) Build ID: 6a1f66be38b523095ebd6ec13cc15820cede903d + + Displaying notes found in: .note.FRR + Owner Data size Description + FRRouting 0x00000010 Unknown note type: (0x46455258) description data: 6c eb 15 00 00 00 00 00 74 ec 15 00 00 00 00 00 + +Where 0x15eb6c…0x15ec74 are the offsets (relative to the note itself) where +the xref array is in the file. Also note the owner is clearly marked as +"FRRouting" and the type is "XREF" in hex. + +For SystemTap's use of ELF notes, refer to +https://libstapsdt.readthedocs.io/en/latest/how-it-works/internals.html as an +entry point. + +.. note:: + + Due to GCC bug 41091, the "xref_array" section is not correctly generated + for C++ code when compiled by GCC. A workaround is present for runtime + functionality, but to extract the xrefs from a C++ source file, it needs + to be built with clang (or a future fixed version of GCC) instead. diff --git a/doc/figures/pcep_module_threading_overview.svg b/doc/figures/pcep_module_threading_overview.svg new file mode 100644 index 0000000000..4d2d2a254a --- /dev/null +++ b/doc/figures/pcep_module_threading_overview.svg @@ -0,0 +1,481 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"> +<svg version="1.2" width="210mm" height="297mm" viewBox="0 0 21000 29700" preserveAspectRatio="xMidYMid" fill-rule="evenodd" stroke-width="28.222" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg" xmlns:ooo="http://xml.openoffice.org/svg/export" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:presentation="http://sun.com/xmlns/staroffice/presentation" xmlns:smil="http://www.w3.org/2001/SMIL20/" xmlns:anim="urn:oasis:names:tc:opendocument:xmlns:animation:1.0" xml:space="preserve"> + <defs class="ClipPathGroup"> + <clipPath id="presentation_clip_path" clipPathUnits="userSpaceOnUse"> + <rect x="0" y="0" width="21000" height="29700"/> + </clipPath> + <clipPath id="presentation_clip_path_shrink" clipPathUnits="userSpaceOnUse"> + <rect x="21" y="29" width="20958" height="29641"/> + </clipPath> + </defs> + <defs> + <font id="EmbeddedFont_1" horiz-adv-x="2048"> + <font-face font-family="Liberation Sans embedded" units-per-em="2048" font-weight="normal" font-style="normal" ascent="1852" descent="423"/> + <missing-glyph horiz-adv-x="2048" d="M 0,0 L 2047,0 2047,2047 0,2047 0,0 Z"/> + <glyph unicode="u" horiz-adv-x="874" d="M 314,1082 L 314,396 C 314,325 321,269 335,230 349,191 371,162 402,145 433,128 478,119 537,119 624,119 692,149 742,208 792,267 817,350 817,455 L 817,1082 997,1082 997,231 C 997,105 999,28 1003,0 L 833,0 C 832,3 832,12 831,27 830,42 830,59 829,78 828,97 826,132 825,185 L 822,185 C 781,110 733,58 679,27 624,-4 557,-20 476,-20 357,-20 271,10 216,69 161,128 133,225 133,361 L 133,1082 314,1082 Z"/> + <glyph unicode="t" horiz-adv-x="531" d="M 554,8 C 495,-8 434,-16 372,-16 228,-16 156,66 156,229 L 156,951 31,951 31,1082 163,1082 216,1324 336,1324 336,1082 536,1082 536,951 336,951 336,268 C 336,216 345,180 362,159 379,138 408,127 450,127 474,127 509,132 554,141 L 554,8 Z"/> + <glyph unicode="r" horiz-adv-x="530" d="M 142,0 L 142,830 C 142,906 140,990 136,1082 L 306,1082 C 311,959 314,886 314,861 L 318,861 C 347,954 380,1017 417,1051 454,1085 507,1102 575,1102 599,1102 623,1099 648,1092 L 648,927 C 624,934 592,937 552,937 477,937 420,905 381,841 342,776 322,684 322,564 L 322,0 142,0 Z"/> + <glyph unicode="p" horiz-adv-x="953" d="M 1053,546 C 1053,169 920,-20 655,-20 488,-20 376,43 319,168 L 314,168 C 317,163 318,106 318,-2 L 318,-425 138,-425 138,861 C 138,972 136,1046 132,1082 L 306,1082 C 307,1079 308,1070 309,1054 310,1037 312,1012 314,978 315,944 316,921 316,908 L 320,908 C 352,975 394,1024 447,1055 500,1086 569,1101 655,1101 788,1101 888,1056 954,967 1020,878 1053,737 1053,546 Z M 864,542 C 864,693 844,800 803,865 762,930 698,962 609,962 538,962 482,947 442,917 401,887 371,840 350,777 329,713 318,630 318,528 318,386 341,281 386,214 431,147 505,113 607,113 696,113 762,146 803,212 844,277 864,387 864,542 Z"/> + <glyph unicode="o" horiz-adv-x="980" d="M 1053,542 C 1053,353 1011,212 928,119 845,26 724,-20 565,-20 407,-20 288,28 207,125 126,221 86,360 86,542 86,915 248,1102 571,1102 736,1102 858,1057 936,966 1014,875 1053,733 1053,542 Z M 864,542 C 864,691 842,800 798,868 753,935 679,969 574,969 469,969 393,935 346,866 299,797 275,689 275,542 275,399 298,292 345,221 391,149 464,113 563,113 671,113 748,148 795,217 841,286 864,395 864,542 Z"/> + <glyph unicode="n" horiz-adv-x="874" d="M 825,0 L 825,686 C 825,757 818,813 804,852 790,891 768,920 737,937 706,954 661,963 602,963 515,963 447,933 397,874 347,815 322,732 322,627 L 322,0 142,0 142,851 C 142,977 140,1054 136,1082 L 306,1082 C 307,1079 307,1070 308,1055 309,1040 310,1024 311,1005 312,986 313,950 314,897 L 317,897 C 358,972 406,1025 461,1056 515,1087 582,1102 663,1102 782,1102 869,1073 924,1014 979,955 1006,857 1006,721 L 1006,0 825,0 Z"/> + <glyph unicode="l" horiz-adv-x="187" d="M 138,0 L 138,1484 318,1484 318,0 138,0 Z"/> + <glyph unicode="i" horiz-adv-x="187" d="M 137,1312 L 137,1484 317,1484 317,1312 137,1312 Z M 137,0 L 137,1082 317,1082 317,0 137,0 Z"/> + <glyph unicode="h" horiz-adv-x="874" d="M 317,897 C 356,968 402,1020 457,1053 511,1086 580,1102 663,1102 780,1102 867,1073 923,1015 978,956 1006,858 1006,721 L 1006,0 825,0 825,686 C 825,762 818,819 804,856 790,893 767,920 735,937 703,954 659,963 602,963 517,963 450,934 399,875 348,816 322,737 322,638 L 322,0 142,0 142,1484 322,1484 322,1098 C 322,1057 321,1015 319,972 316,929 315,904 314,897 L 317,897 Z"/> + <glyph unicode="e" horiz-adv-x="980" d="M 276,503 C 276,379 302,283 353,216 404,149 479,115 578,115 656,115 719,131 766,162 813,193 844,233 861,281 L 1019,236 C 954,65 807,-20 578,-20 418,-20 296,28 213,123 129,218 87,360 87,548 87,727 129,864 213,959 296,1054 416,1102 571,1102 889,1102 1048,910 1048,527 L 1048,503 276,503 Z M 862,641 C 852,755 823,838 775,891 727,943 658,969 568,969 481,969 412,940 361,882 310,823 282,743 278,641 L 862,641 Z"/> + <glyph unicode="d" horiz-adv-x="927" d="M 821,174 C 788,105 744,55 689,25 634,-5 565,-20 484,-20 347,-20 247,26 183,118 118,210 86,349 86,536 86,913 219,1102 484,1102 566,1102 634,1087 689,1057 744,1027 788,979 821,914 L 823,914 821,1035 821,1484 1001,1484 1001,223 C 1001,110 1003,36 1007,0 L 835,0 C 833,11 831,35 829,74 826,113 825,146 825,174 L 821,174 Z M 275,542 C 275,391 295,282 335,217 375,152 440,119 530,119 632,119 706,154 752,225 798,296 821,405 821,554 821,697 798,802 752,869 706,936 633,969 532,969 441,969 376,936 336,869 295,802 275,693 275,542 Z"/> + <glyph unicode="c" horiz-adv-x="901" d="M 275,546 C 275,402 298,295 343,226 388,157 457,122 548,122 612,122 666,139 709,174 752,209 778,262 788,334 L 970,322 C 956,218 912,135 837,73 762,11 668,-20 553,-20 402,-20 286,28 207,124 127,219 87,359 87,542 87,724 127,863 207,959 287,1054 402,1102 551,1102 662,1102 754,1073 827,1016 900,959 945,880 964,779 L 779,765 C 770,825 746,873 708,908 670,943 616,961 546,961 451,961 382,929 339,866 296,803 275,696 275,546 Z"/> + <glyph unicode="b" horiz-adv-x="953" d="M 1053,546 C 1053,169 920,-20 655,-20 573,-20 505,-5 451,25 396,54 352,102 318,168 L 316,168 C 316,147 315,116 312,74 309,31 307,7 306,0 L 132,0 C 136,36 138,110 138,223 L 138,1484 318,1484 318,1061 C 318,1018 317,967 314,908 L 318,908 C 351,977 396,1027 451,1057 506,1087 574,1102 655,1102 792,1102 892,1056 957,964 1021,872 1053,733 1053,546 Z M 864,540 C 864,691 844,800 804,865 764,930 699,963 609,963 508,963 434,928 388,859 341,790 318,680 318,529 318,387 341,282 386,215 431,147 505,113 607,113 698,113 763,147 804,214 844,281 864,389 864,540 Z"/> + <glyph unicode="a" horiz-adv-x="1060" d="M 414,-20 C 305,-20 224,9 169,66 114,123 87,202 87,302 87,414 124,500 198,560 271,620 390,652 554,656 L 797,660 797,719 C 797,807 778,870 741,908 704,946 645,965 565,965 484,965 426,951 389,924 352,897 330,853 323,793 L 135,810 C 166,1005 310,1102 569,1102 705,1102 807,1071 876,1009 945,946 979,856 979,738 L 979,272 C 979,219 986,179 1000,152 1014,125 1041,111 1080,111 1097,111 1117,113 1139,118 L 1139,6 C 1094,-5 1047,-10 1000,-10 933,-10 885,8 855,43 824,78 807,132 803,207 L 797,207 C 751,124 698,66 637,32 576,-3 501,-20 414,-20 Z M 455,115 C 521,115 580,130 631,160 682,190 723,231 753,284 782,336 797,390 797,445 L 797,534 600,530 C 515,529 451,520 408,504 364,488 330,463 307,430 284,397 272,353 272,299 272,240 288,195 320,163 351,131 396,115 455,115 Z"/> + <glyph unicode="_" horiz-adv-x="1218" d="M -31,-407 L -31,-277 1162,-277 1162,-407 -31,-407 Z"/> + <glyph unicode="Y" horiz-adv-x="1298" d="M 777,584 L 777,0 587,0 587,584 45,1409 255,1409 684,738 1111,1409 1321,1409 777,584 Z"/> + <glyph unicode="X" horiz-adv-x="1298" d="M 1112,0 L 689,616 257,0 46,0 582,732 87,1409 298,1409 690,856 1071,1409 1282,1409 800,739 1323,0 1112,0 Z"/> + <glyph unicode="V" horiz-adv-x="1377" d="M 782,0 L 584,0 9,1409 210,1409 600,417 684,168 768,417 1156,1409 1357,1409 782,0 Z"/> + <glyph unicode="T" horiz-adv-x="1192" d="M 720,1253 L 720,0 530,0 530,1253 46,1253 46,1409 1204,1409 1204,1253 720,1253 Z"/> + <glyph unicode="S" horiz-adv-x="1192" d="M 1272,389 C 1272,259 1221,158 1120,87 1018,16 875,-20 690,-20 347,-20 148,99 93,338 L 278,375 C 299,290 345,228 414,189 483,149 578,129 697,129 820,129 916,150 983,193 1050,235 1083,297 1083,379 1083,425 1073,462 1052,491 1031,520 1001,543 963,562 925,581 880,596 827,609 774,622 716,635 652,650 541,675 456,699 399,724 341,749 295,776 262,807 229,837 203,872 186,913 168,954 159,1000 159,1053 159,1174 205,1267 298,1332 390,1397 522,1430 694,1430 854,1430 976,1406 1061,1357 1146,1308 1205,1224 1239,1106 L 1051,1073 C 1030,1148 991,1202 933,1236 875,1269 795,1286 692,1286 579,1286 493,1267 434,1230 375,1193 345,1137 345,1063 345,1020 357,984 380,956 403,927 436,903 479,884 522,864 609,840 738,811 781,801 825,791 868,781 911,770 952,758 991,744 1030,729 1067,712 1102,693 1136,674 1166,650 1191,622 1216,594 1236,561 1251,523 1265,485 1272,440 1272,389 Z"/> + <glyph unicode="R" horiz-adv-x="1244" d="M 1164,0 L 798,585 359,585 359,0 168,0 168,1409 831,1409 C 990,1409 1112,1374 1199,1303 1285,1232 1328,1133 1328,1006 1328,901 1298,813 1237,742 1176,671 1091,626 984,607 L 1384,0 1164,0 Z M 1136,1004 C 1136,1086 1108,1149 1053,1192 997,1235 917,1256 812,1256 L 359,1256 359,736 820,736 C 921,736 999,760 1054,807 1109,854 1136,919 1136,1004 Z"/> + <glyph unicode="P" horiz-adv-x="1112" d="M 1258,985 C 1258,852 1215,746 1128,667 1041,588 922,549 773,549 L 359,549 359,0 168,0 168,1409 761,1409 C 919,1409 1041,1372 1128,1298 1215,1224 1258,1120 1258,985 Z M 1066,983 C 1066,1165 957,1256 738,1256 L 359,1256 359,700 746,700 C 959,700 1066,794 1066,983 Z"/> + <glyph unicode="O" horiz-adv-x="1430" d="M 1495,711 C 1495,564 1467,435 1411,324 1354,213 1273,128 1168,69 1063,10 938,-20 795,-20 650,-20 526,9 421,68 316,127 235,212 180,323 125,434 97,563 97,711 97,936 159,1113 282,1240 405,1367 577,1430 797,1430 940,1430 1065,1402 1170,1345 1275,1288 1356,1205 1412,1096 1467,987 1495,859 1495,711 Z M 1300,711 C 1300,886 1256,1024 1169,1124 1081,1224 957,1274 797,1274 636,1274 511,1225 423,1126 335,1027 291,889 291,711 291,534 336,394 425,291 514,187 637,135 795,135 958,135 1083,185 1170,286 1257,386 1300,528 1300,711 Z"/> + <glyph unicode="N" horiz-adv-x="1165" d="M 1082,0 L 328,1200 333,1103 338,936 338,0 168,0 168,1409 390,1409 1152,201 C 1144,332 1140,426 1140,485 L 1140,1409 1312,1409 1312,0 1082,0 Z"/> + <glyph unicode="M" horiz-adv-x="1377" d="M 1366,0 L 1366,940 C 1366,1044 1369,1144 1375,1240 1342,1121 1313,1027 1287,960 L 923,0 789,0 420,960 364,1130 331,1240 334,1129 338,940 338,0 168,0 168,1409 419,1409 794,432 C 807,393 820,351 833,306 845,261 853,228 857,208 862,235 874,275 891,330 908,384 919,418 925,432 L 1293,1409 1538,1409 1538,0 1366,0 Z"/> + <glyph unicode="L" horiz-adv-x="927" d="M 168,0 L 168,1409 359,1409 359,156 1071,156 1071,0 168,0 Z"/> + <glyph unicode="I" horiz-adv-x="213" d="M 189,0 L 189,1409 380,1409 380,0 189,0 Z"/> + <glyph unicode="H" horiz-adv-x="1165" d="M 1121,0 L 1121,653 359,653 359,0 168,0 168,1409 359,1409 359,813 1121,813 1121,1409 1312,1409 1312,0 1121,0 Z"/> + <glyph unicode="F" horiz-adv-x="1006" d="M 359,1253 L 359,729 1145,729 1145,571 359,571 359,0 168,0 168,1409 1169,1409 1169,1253 359,1253 Z"/> + <glyph unicode="E" horiz-adv-x="1138" d="M 168,0 L 168,1409 1237,1409 1237,1253 359,1253 359,801 1177,801 1177,647 359,647 359,156 1278,156 1278,0 168,0 Z"/> + <glyph unicode="D" horiz-adv-x="1218" d="M 1381,719 C 1381,574 1353,447 1296,338 1239,229 1159,145 1055,87 951,29 831,0 695,0 L 168,0 168,1409 634,1409 C 873,1409 1057,1349 1187,1230 1316,1110 1381,940 1381,719 Z M 1189,719 C 1189,894 1141,1027 1046,1119 950,1210 811,1256 630,1256 L 359,1256 359,153 673,153 C 776,153 867,176 946,221 1024,266 1084,332 1126,417 1168,502 1189,603 1189,719 Z"/> + <glyph unicode="C" horiz-adv-x="1324" d="M 792,1274 C 636,1274 515,1224 428,1124 341,1023 298,886 298,711 298,538 343,400 434,295 524,190 646,137 800,137 997,137 1146,235 1245,430 L 1401,352 C 1343,231 1262,138 1157,75 1052,12 930,-20 791,-20 649,-20 526,10 423,69 319,128 240,212 186,322 131,431 104,561 104,711 104,936 165,1112 286,1239 407,1366 575,1430 790,1430 940,1430 1065,1401 1166,1342 1267,1283 1341,1196 1388,1081 L 1207,1021 C 1174,1103 1122,1166 1050,1209 977,1252 891,1274 792,1274 Z"/> + <glyph unicode="B" horiz-adv-x="1112" d="M 1258,397 C 1258,272 1212,174 1121,105 1030,35 903,0 740,0 L 168,0 168,1409 680,1409 C 1011,1409 1176,1295 1176,1067 1176,984 1153,914 1106,857 1059,800 993,762 908,743 1020,730 1106,692 1167,631 1228,569 1258,491 1258,397 Z M 984,1044 C 984,1120 958,1174 906,1207 854,1240 779,1256 680,1256 L 359,1256 359,810 680,810 C 782,810 858,829 909,868 959,906 984,965 984,1044 Z M 1065,412 C 1065,578 948,661 715,661 L 359,661 359,153 730,153 C 847,153 932,175 985,218 1038,261 1065,326 1065,412 Z"/> + <glyph unicode="A" horiz-adv-x="1377" d="M 1167,0 L 1006,412 364,412 202,0 4,0 579,1409 796,1409 1362,0 1167,0 Z M 685,1265 L 676,1237 C 659,1182 635,1111 602,1024 L 422,561 949,561 768,1026 C 749,1072 731,1124 712,1182 L 685,1265 Z"/> + <glyph unicode=" " horiz-adv-x="556"/> + </font> + </defs> + <defs class="TextShapeIndex"> + <g ooo:slide="id1" ooo:id-list="id3 id4 id5 id6 id7 id8 id9 id10 id11 id12 id13 id14 id15 id16 id17 id18 id19 id20 id21 id22 id23 id24 id25 id26 id27 id28"/> + </defs> + <defs class="EmbeddedBulletChars"> + <g id="bullet-char-template-57356" transform="scale(0.00048828125,-0.00048828125)"> + <path d="M 580,1141 L 1163,571 580,0 -4,571 580,1141 Z"/> + </g> + <g id="bullet-char-template-57354" transform="scale(0.00048828125,-0.00048828125)"> + <path d="M 8,1128 L 1137,1128 1137,0 8,0 8,1128 Z"/> + </g> + <g id="bullet-char-template-10146" transform="scale(0.00048828125,-0.00048828125)"> + <path d="M 174,0 L 602,739 174,1481 1456,739 174,0 Z M 1358,739 L 309,1346 659,739 1358,739 Z"/> + </g> + <g id="bullet-char-template-10132" transform="scale(0.00048828125,-0.00048828125)"> + <path d="M 2015,739 L 1276,0 717,0 1260,543 174,543 174,936 1260,936 717,1481 1274,1481 2015,739 Z"/> + </g> + <g id="bullet-char-template-10007" transform="scale(0.00048828125,-0.00048828125)"> + <path d="M 0,-2 C -7,14 -16,27 -25,37 L 356,567 C 262,823 215,952 215,954 215,979 228,992 255,992 264,992 276,990 289,987 310,991 331,999 354,1012 L 381,999 492,748 772,1049 836,1024 860,1049 C 881,1039 901,1025 922,1006 886,937 835,863 770,784 769,783 710,716 594,584 L 774,223 C 774,196 753,168 711,139 L 727,119 C 717,90 699,76 672,76 641,76 570,178 457,381 L 164,-76 C 142,-110 111,-127 72,-127 30,-127 9,-110 8,-76 1,-67 -2,-52 -2,-32 -2,-23 -1,-13 0,-2 Z"/> + </g> + <g id="bullet-char-template-10004" transform="scale(0.00048828125,-0.00048828125)"> + <path d="M 285,-33 C 182,-33 111,30 74,156 52,228 41,333 41,471 41,549 55,616 82,672 116,743 169,778 240,778 293,778 328,747 346,684 L 369,508 C 377,444 397,411 428,410 L 1163,1116 C 1174,1127 1196,1133 1229,1133 1271,1133 1292,1118 1292,1087 L 1292,965 C 1292,929 1282,901 1262,881 L 442,47 C 390,-6 338,-33 285,-33 Z"/> + </g> + <g id="bullet-char-template-9679" transform="scale(0.00048828125,-0.00048828125)"> + <path d="M 813,0 C 632,0 489,54 383,161 276,268 223,411 223,592 223,773 276,916 383,1023 489,1130 632,1184 813,1184 992,1184 1136,1130 1245,1023 1353,916 1407,772 1407,592 1407,412 1353,268 1245,161 1136,54 992,0 813,0 Z"/> + </g> + <g id="bullet-char-template-8226" transform="scale(0.00048828125,-0.00048828125)"> + <path d="M 346,457 C 273,457 209,483 155,535 101,586 74,649 74,723 74,796 101,859 155,911 209,963 273,989 346,989 419,989 480,963 531,910 582,859 608,796 608,723 608,648 583,586 532,535 482,483 420,457 346,457 Z"/> + </g> + <g id="bullet-char-template-8211" transform="scale(0.00048828125,-0.00048828125)"> + <path d="M -4,459 L 1135,459 1135,606 -4,606 -4,459 Z"/> + </g> + <g id="bullet-char-template-61548" transform="scale(0.00048828125,-0.00048828125)"> + <path d="M 173,740 C 173,903 231,1043 346,1159 462,1274 601,1332 765,1332 928,1332 1067,1274 1183,1159 1299,1043 1357,903 1357,740 1357,577 1299,437 1183,322 1067,206 928,148 765,148 601,148 462,206 346,322 231,437 173,577 173,740 Z"/> + </g> + </defs> + <defs class="TextEmbeddedBitmaps"/> + <g> + <g id="id2" class="Master_Slide"> + <g id="bg-id2" class="Background"/> + <g id="bo-id2" class="BackgroundObjects"/> + </g> + </g> + <g class="SlideGroup"> + <g> + <g id="container-id1"> + <g id="id1" class="Slide" clip-path="url(#presentation_clip_path)"> + <g class="Page"> + <g class="com.sun.star.drawing.CustomShape"> + <g id="id3"> + <rect class="BoundingBox" stroke="none" fill="none" x="9227" y="2229" width="7040" height="8959"/> + <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 12771,11160 L 12747,11160 12642,11160"/> + <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 12578,11160 L 12474,11160"/> + <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 12410,11160 L 12306,11160"/> + <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 12242,11160 L 12138,11160"/> + <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 12074,11160 L 11970,11160"/> + <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 11906,11160 L 11802,11160"/> + <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 11738,11160 L 11634,11160"/> + <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 11570,11160 L 11466,11160"/> + <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 11402,11160 L 11298,11160"/> + <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 11234,11160 L 11130,11160"/> + <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 11066,11160 L 10962,11160"/> + <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 10898,11160 L 10794,11160"/> + <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 10730,11160 L 10626,11160"/> + <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 10562,11160 L 10458,11160"/> + <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 10394,11160 L 10290,11160"/> + <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 10226,11160 L 10122,11160"/> + <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 10058,11160 L 9954,11160"/> + <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 9890,11160 L 9786,11160"/> + <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 9722,11160 L 9618,11160"/> + <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 9554,11160 L 9450,11160"/> + <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 9386,11160 L 9282,11160"/> + <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 9254,11124 L 9254,11020"/> + <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 9254,10956 L 9254,10852"/> + <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 9254,10788 L 9254,10684"/> + <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 9254,10620 L 9254,10516"/> + <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 9254,10452 L 9254,10348"/> + <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 9254,10284 L 9254,10180"/> + <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 9254,10116 L 9254,10012"/> + <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 9254,9948 L 9254,9844"/> + <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 9254,9780 L 9254,9676"/> + <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 9254,9612 L 9254,9508"/> + <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 9254,9444 L 9254,9340"/> + <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 9254,9276 L 9254,9172"/> + <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 9254,9108 L 9254,9004"/> + <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 9254,8940 L 9254,8836"/> + <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 9254,8772 L 9254,8668"/> + <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 9254,8604 L 9254,8500"/> + <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 9254,8436 L 9254,8332"/> + <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 9254,8268 L 9254,8164"/> + <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 9254,8100 L 9254,7996"/> + <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 9254,7932 L 9254,7828"/> + <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 9254,7764 L 9254,7660"/> + <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 9254,7596 L 9254,7492"/> + <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 9254,7428 L 9254,7324"/> + <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 9254,7260 L 9254,7156"/> + <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 9254,7092 L 9254,6988"/> + <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 9254,6924 L 9254,6820"/> + <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 9254,6756 L 9254,6652"/> + <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 9254,6588 L 9254,6484"/> + <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 9254,6420 L 9254,6316"/> + <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 9254,6252 L 9254,6148"/> + <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 9254,6084 L 9254,5980"/> + <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 9254,5916 L 9254,5812"/> + <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 9254,5748 L 9254,5644"/> + <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 9254,5580 L 9254,5476"/> + <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 9254,5412 L 9254,5308"/> + <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 9254,5244 L 9254,5140"/> + <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 9254,5076 L 9254,4972"/> + <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 9254,4908 L 9254,4804"/> + <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 9254,4740 L 9254,4636"/> + <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 9254,4572 L 9254,4467"/> + <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 9254,4404 L 9254,4299"/> + <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 9254,4236 L 9254,4131"/> + <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 9254,4068 L 9254,3963"/> + <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 9254,3900 L 9254,3795"/> + <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 9254,3732 L 9254,3627"/> + <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 9254,3564 L 9254,3459"/> + <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 9254,3396 L 9254,3291"/> + <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 9254,3228 L 9254,3123"/> + <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 9254,3060 L 9254,2955"/> + <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 9254,2892 L 9254,2787"/> + <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 9254,2724 L 9254,2619"/> + <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 9254,2556 L 9254,2451"/> + <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 9254,2388 L 9254,2283"/> + <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 9290,2256 L 9395,2256"/> + <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 9458,2256 L 9563,2256"/> + <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 9626,2256 L 9731,2256"/> + <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 9794,2256 L 9899,2256"/> + <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 9962,2256 L 10067,2256"/> + <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 10130,2256 L 10235,2256"/> + <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 10298,2256 L 10403,2256"/> + <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 10466,2256 L 10571,2256"/> + <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 10634,2256 L 10739,2256"/> + <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 10802,2256 L 10907,2256"/> + <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 10970,2256 L 11075,2256"/> + <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 11138,2256 L 11243,2256"/> + <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 11306,2256 L 11411,2256"/> + <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 11474,2256 L 11579,2256"/> + <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 11642,2256 L 11747,2256"/> + <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 11810,2256 L 11915,2256"/> + <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 11978,2256 L 12083,2256"/> + <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 12146,2256 L 12251,2256"/> + <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 12314,2256 L 12419,2256"/> + <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 12482,2256 L 12587,2256"/> + <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 12650,2256 L 12755,2256"/> + <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 12818,2256 L 12923,2256"/> + <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 12986,2256 L 13091,2256"/> + <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 13154,2256 L 13259,2256"/> + <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 13322,2256 L 13427,2256"/> + <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 13490,2256 L 13595,2256"/> + <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 13659,2256 L 13763,2256"/> + <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 13827,2256 L 13931,2256"/> + <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 13995,2256 L 14099,2256"/> + <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 14163,2256 L 14267,2256"/> + <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 14331,2256 L 14435,2256"/> + <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 14499,2256 L 14603,2256"/> + <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 14667,2256 L 14771,2256"/> + <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 14835,2256 L 14939,2256"/> + <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 15003,2256 L 15107,2256"/> + <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 15171,2256 L 15275,2256"/> + <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 15339,2256 L 15443,2256"/> + <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 15507,2256 L 15611,2256"/> + <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 15675,2256 L 15779,2256"/> + <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 15843,2256 L 15947,2256"/> + <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 16011,2256 L 16115,2256"/> + <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 16179,2256 L 16239,2256 16239,2300"/> + <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 16239,2364 L 16239,2468"/> + <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 16239,2532 L 16239,2636"/> + <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 16239,2700 L 16239,2804"/> + <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 16239,2868 L 16239,2972"/> + <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 16239,3036 L 16239,3140"/> + <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 16239,3204 L 16239,3308"/> + <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 16239,3372 L 16239,3476"/> + <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 16239,3540 L 16239,3644"/> + <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 16239,3708 L 16239,3812"/> + <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 16239,3876 L 16239,3980"/> + <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 16239,4044 L 16239,4148"/> + <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 16239,4212 L 16239,4316"/> + <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 16239,4380 L 16239,4484"/> + <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 16239,4548 L 16239,4652"/> + <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 16239,4716 L 16239,4820"/> + <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 16239,4884 L 16239,4988"/> + <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 16239,5052 L 16239,5156"/> + <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 16239,5220 L 16239,5324"/> + <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 16239,5388 L 16239,5492"/> + <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 16239,5556 L 16239,5660"/> + <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 16239,5724 L 16239,5828"/> + <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 16239,5892 L 16239,5996"/> + <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 16239,6060 L 16239,6164"/> + <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 16239,6228 L 16239,6332"/> + <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 16239,6396 L 16239,6500"/> + <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 16239,6564 L 16239,6668"/> + <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 16239,6732 L 16239,6836"/> + <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 16239,6900 L 16239,7004"/> + <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 16239,7068 L 16239,7172"/> + <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 16239,7236 L 16239,7340"/> + <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 16239,7404 L 16239,7508"/> + <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 16239,7572 L 16239,7676"/> + <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 16239,7740 L 16239,7844"/> + <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 16239,7908 L 16239,8012"/> + <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 16239,8076 L 16239,8180"/> + <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 16239,8244 L 16239,8348"/> + <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 16239,8412 L 16239,8516"/> + <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 16239,8580 L 16239,8684"/> + <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 16239,8748 L 16239,8852"/> + <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 16239,8916 L 16239,9020"/> + <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 16239,9084 L 16239,9188"/> + <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 16239,9252 L 16239,9356"/> + <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 16239,9420 L 16239,9524"/> + <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 16239,9588 L 16239,9693"/> + <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 16239,9756 L 16239,9861"/> + <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 16239,9924 L 16239,10029"/> + <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 16239,10092 L 16239,10197"/> + <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 16239,10260 L 16239,10365"/> + <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 16239,10428 L 16239,10533"/> + <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 16239,10596 L 16239,10701"/> + <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 16239,10764 L 16239,10869"/> + <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 16239,10932 L 16239,11037"/> + <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 16239,11100 L 16239,11160 16194,11160"/> + <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 16131,11160 L 16026,11160"/> + <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 15963,11160 L 15858,11160"/> + <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 15795,11160 L 15690,11160"/> + <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 15627,11160 L 15522,11160"/> + <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 15459,11160 L 15354,11160"/> + <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 15291,11160 L 15186,11160"/> + <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 15123,11160 L 15018,11160"/> + <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 14955,11160 L 14850,11160"/> + <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 14787,11160 L 14682,11160"/> + <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 14619,11160 L 14514,11160"/> + <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 14451,11160 L 14346,11160"/> + <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 14283,11160 L 14178,11160"/> + <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 14115,11160 L 14010,11160"/> + <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 13947,11160 L 13842,11160"/> + <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 13779,11160 L 13674,11160"/> + <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 13611,11160 L 13506,11160"/> + <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 13443,11160 L 13338,11160"/> + <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 13275,11160 L 13170,11160"/> + <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 13107,11160 L 13002,11160"/> + <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 12939,11160 L 12834,11160"/> + </g> + </g> + <g class="com.sun.star.drawing.TextShape"> + <g id="id4"> + <rect class="BoundingBox" stroke="none" fill="none" x="3128" y="2360" width="5723" height="840"/> + <text class="TextShape"><tspan class="TextParagraph" font-family="Liberation Sans, sans-serif" font-size="529px" font-weight="400"><tspan class="TextPosition" x="3378" y="2963"><tspan fill="rgb(0,102,179)" stroke="none">MAIN PTHREAD</tspan></tspan></tspan></text> + </g> + </g> + <g class="com.sun.star.drawing.TextShape"> + <g id="id5"> + <rect class="BoundingBox" stroke="none" fill="none" x="9640" y="2360" width="8013" height="840"/> + <text class="TextShape"><tspan class="TextParagraph" font-family="Liberation Sans, sans-serif" font-size="529px" font-weight="400"><tspan class="TextPosition" x="9890" y="2963"><tspan fill="rgb(0,102,179)" stroke="none">CONTROLLER PTHREAD</tspan></tspan></tspan></text> + </g> + </g> + <g class="com.sun.star.drawing.CustomShape"> + <g id="id6"> + <rect class="BoundingBox" stroke="none" fill="none" x="3315" y="5190" width="2797" height="1273"/> + <path fill="rgb(114,159,207)" stroke="none" d="M 4713,6461 L 3316,6461 3316,5191 6110,5191 6110,6461 4713,6461 Z"/> + <path fill="none" stroke="rgb(52,101,164)" d="M 4713,6461 L 3316,6461 3316,5191 6110,5191 6110,6461 4713,6461 Z"/> + <text class="TextShape"><tspan class="TextParagraph" font-family="Liberation Sans, sans-serif" font-size="459px" font-weight="400"><tspan class="TextPosition" x="4358" y="5985"><tspan fill="rgb(0,0,0)" stroke="none">CLI</tspan></tspan></tspan></text> + </g> + </g> + <g class="com.sun.star.drawing.CustomShape"> + <g id="id7"> + <rect class="BoundingBox" stroke="none" fill="none" x="3315" y="7349" width="2797" height="1273"/> + <path fill="rgb(114,159,207)" stroke="none" d="M 4713,8620 L 3316,8620 3316,7350 6110,7350 6110,8620 4713,8620 Z"/> + <path fill="none" stroke="rgb(52,101,164)" d="M 4713,8620 L 3316,8620 3316,7350 6110,7350 6110,8620 4713,8620 Z"/> + <text class="TextShape"><tspan class="TextParagraph" font-family="Liberation Sans, sans-serif" font-size="459px" font-weight="400"><tspan class="TextPosition" x="3972" y="7888"><tspan fill="rgb(0,0,0)" stroke="none">PATHD</tspan></tspan></tspan><tspan class="TextParagraph" font-family="Liberation Sans, sans-serif" font-size="459px" font-weight="400"><tspan class="TextPosition" x="3430" y="8400"><tspan fill="rgb(0,0,0)" stroke="none">INTERFACE</tspan></tspan></tspan></text> + </g> + </g> + <g class="com.sun.star.drawing.CustomShape"> + <g id="id8"> + <rect class="BoundingBox" stroke="none" fill="none" x="12459" y="6079" width="2797" height="1273"/> + <path fill="rgb(114,159,207)" stroke="none" d="M 13857,7350 L 12460,7350 12460,6080 15254,6080 15254,7350 13857,7350 Z"/> + <path fill="none" stroke="rgb(52,101,164)" d="M 13857,7350 L 12460,7350 12460,6080 15254,6080 15254,7350 13857,7350 Z"/> + <text class="TextShape"><tspan class="TextParagraph" font-family="Liberation Sans, sans-serif" font-size="459px" font-weight="400"><tspan class="TextPosition" x="13375" y="6874"><tspan fill="rgb(0,0,0)" stroke="none">PCC</tspan></tspan></tspan></text> + </g> + </g> + <g class="com.sun.star.drawing.LineShape"> + <g id="id9"> + <rect class="BoundingBox" stroke="none" fill="none" x="1665" y="7578" width="2033" height="205"/> + <path fill="none" stroke="rgb(102,102,102)" stroke-width="35" stroke-linejoin="round" d="M 1956,7680 L 3406,7680"/> + <path fill="rgb(102,102,102)" stroke="none" d="M 1665,7680 L 1970,7782 1970,7579 1665,7680 Z"/> + <path fill="rgb(102,102,102)" stroke="none" d="M 3697,7680 L 3393,7579 3393,7782 3697,7680 Z"/> + </g> + </g> + <g class="com.sun.star.drawing.TextShape"> + <g id="id10"> + <rect class="BoundingBox" stroke="none" fill="none" x="1892" y="5137" width="1451" height="570"/> + <text class="TextShape"><tspan class="TextParagraph" font-family="Liberation Sans, sans-serif" font-size="282px" font-weight="400"><tspan class="TextPosition" x="2142" y="5520"><tspan fill="rgb(0,0,0)" stroke="none">VTYSH</tspan></tspan></tspan></text> + </g> + </g> + <g class="com.sun.star.drawing.TextShape"> + <g id="id11"> + <rect class="BoundingBox" stroke="none" fill="none" x="1568" y="5738" width="1976" height="570"/> + <text class="TextShape"><tspan class="TextParagraph" font-family="Liberation Sans, sans-serif" font-size="282px" font-weight="400"><tspan class="TextPosition" x="1818" y="6121"><tspan fill="rgb(0,0,0)" stroke="none">Northbound</tspan></tspan></tspan></text> + </g> + </g> + <g class="com.sun.star.drawing.TextShape"> + <g id="id12"> + <rect class="BoundingBox" stroke="none" fill="none" x="1738" y="7235" width="1735" height="570"/> + <text class="TextShape"><tspan class="TextParagraph" font-family="Liberation Sans, sans-serif" font-size="282px" font-weight="400"><tspan class="TextPosition" x="1988" y="7618"><tspan fill="rgb(0,0,0)" stroke="none">pathd API</tspan></tspan></tspan></text> + </g> + </g> + <g class="com.sun.star.drawing.ClosedBezierShape"> + <g id="id13"> + <rect class="BoundingBox" stroke="none" fill="none" x="2299" y="2229" width="6957" height="8959"/> + <path fill="rgb(52,101,164)" stroke="none" d="M 2299,11134 L 2396,11134 2396,11160 2396,11186 2299,11186 2299,11134 Z M 2299,2230 L 2333,2230 2333,2256 2333,2283 2299,2283 2299,2230 Z M 2399,2283 L 2399,2256 2399,2230 2506,2230 2506,2256 2506,2283 2399,2283 Z M 2571,2283 L 2571,2256 2571,2230 2679,2230 2679,2256 2679,2283 2571,2283 Z M 2744,2283 L 2744,2256 2744,2230 2852,2230 2852,2256 2852,2283 2744,2283 Z M 2917,2283 L 2917,2256 2917,2230 3025,2230 3025,2256 3025,2283 2917,2283 Z M 3090,2283 L 3090,2256 3090,2230 3198,2230 3198,2256 3198,2283 3090,2283 Z M 3263,2283 L 3263,2256 3263,2230 3371,2230 3371,2256 3371,2283 3263,2283 Z M 3436,2283 L 3436,2256 3436,2230 3543,2230 3543,2256 3543,2283 3436,2283 Z M 3609,2283 L 3609,2256 3609,2230 3716,2230 3716,2256 3716,2283 3609,2283 Z M 3782,2283 L 3782,2256 3782,2230 3889,2230 3889,2256 3889,2283 3782,2283 Z M 3955,2283 L 3955,2256 3955,2230 4062,2230 4062,2256 4062,2283 3955,2283 Z M 4128,2283 L 4128,2256 4128,2230 4235,2230 4235,2256 4235,2283 4128,2283 Z M 4301,2283 L 4301,2256 4301,2230 4408,2230 4408,2256 4408,2283 4301,2283 Z M 4473,2283 L 4473,2256 4473,2230 4581,2230 4581,2256 4581,2283 4473,2283 Z M 4646,2283 L 4646,2256 4646,2230 4754,2230 4754,2256 4754,2283 4646,2283 Z M 4819,2283 L 4819,2256 4819,2230 4927,2230 4927,2256 4927,2283 4819,2283 Z M 4992,2283 L 4992,2256 4992,2230 5100,2230 5100,2256 5100,2283 4992,2283 Z M 5165,2283 L 5165,2256 5165,2230 5273,2230 5273,2256 5273,2283 5165,2283 Z M 5338,2283 L 5338,2256 5338,2230 5445,2230 5445,2256 5445,2283 5338,2283 Z M 5511,2283 L 5511,2256 5511,2230 5618,2230 5618,2256 5618,2283 5511,2283 Z M 5684,2283 L 5684,2256 5684,2230 5791,2230 5791,2256 5791,2283 5684,2283 Z M 5857,2283 L 5857,2256 5857,2230 5964,2230 5964,2256 5964,2283 5857,2283 Z M 6030,2283 L 6030,2256 6030,2230 6137,2230 6137,2256 6137,2283 6030,2283 Z M 6203,2283 L 6203,2256 6203,2230 6310,2230 6310,2256 6310,2283 6203,2283 Z M 6375,2283 L 6375,2256 6375,2230 6483,2230 6483,2256 6483,2283 6375,2283 Z M 6548,2283 L 6548,2256 6548,2230 6656,2230 6656,2256 6656,2283 6548,2283 Z M 6721,2283 L 6721,2256 6721,2230 6829,2230 6829,2256 6829,2283 6721,2283 Z M 6894,2283 L 6894,2256 6894,2230 7002,2230 7002,2256 7002,2283 6894,2283 Z M 7067,2283 L 7067,2256 7067,2230 7175,2230 7175,2256 7175,2283 7067,2283 Z M 7240,2283 L 7240,2256 7240,2230 7347,2230 7347,2256 7347,2283 7240,2283 Z M 7413,2283 L 7413,2256 7413,2230 7520,2230 7520,2256 7520,2283 7413,2283 Z M 7586,2283 L 7586,2256 7586,2230 7693,2230 7693,2256 7693,2283 7586,2283 Z M 7759,2283 L 7759,2256 7759,2230 7866,2230 7866,2256 7866,2283 7759,2283 Z M 7932,2283 L 7932,2256 7932,2230 8039,2230 8039,2256 8039,2283 7932,2283 Z M 8105,2283 L 8105,2256 8105,2230 8212,2230 8212,2256 8212,2283 8105,2283 Z M 8277,2283 L 8277,2256 8277,2230 8385,2230 8385,2256 8385,2283 8277,2283 Z M 8450,2283 L 8450,2256 8450,2230 8558,2230 8558,2256 8558,2283 8450,2283 Z M 8623,2283 L 8623,2256 8623,2230 8731,2230 8731,2256 8731,2283 8623,2283 Z M 8796,2283 L 8796,2256 8796,2230 8904,2230 8904,2256 8904,2283 8796,2283 Z M 8969,2283 L 8969,2256 8969,2230 9077,2230 9077,2256 9077,2283 8969,2283 Z M 9142,2283 L 9142,2256 9142,2230 9227,2230 C 9232,2230 9237,2231 9241,2233 9245,2235 9248,2239 9251,2243 9253,2247 9254,2251 9254,2256 L 9254,2278 9227,2278 9227,2283 9142,2283 Z M 9200,2341 L 9227,2341 9254,2341 9254,2446 9227,2446 9200,2446 9200,2341 Z M 9200,2509 L 9227,2509 9254,2509 9254,2614 9227,2614 9200,2614 9200,2509 Z M 9200,2677 L 9227,2677 9254,2677 9254,2782 9227,2782 9200,2782 9200,2677 Z M 9200,2845 L 9227,2845 9254,2845 9254,2950 9227,2950 9200,2950 9200,2845 Z M 9200,3013 L 9227,3013 9254,3013 9254,3118 9227,3118 9200,3118 9200,3013 Z M 9200,3181 L 9227,3181 9254,3181 9254,3286 9227,3286 9200,3286 9200,3181 Z M 9200,3349 L 9227,3349 9254,3349 9254,3454 9227,3454 9200,3454 9200,3349 Z M 9200,3517 L 9227,3517 9254,3517 9254,3622 9227,3622 9200,3622 9200,3517 Z M 9200,3685 L 9227,3685 9254,3685 9254,3790 9227,3790 9200,3790 9200,3685 Z M 9200,3853 L 9227,3853 9254,3853 9254,3958 9227,3958 9200,3958 9200,3853 Z M 9200,4021 L 9227,4021 9254,4021 9254,4126 9227,4126 9200,4126 9200,4021 Z M 9200,4189 L 9227,4189 9254,4189 9254,4294 9227,4294 9200,4294 9200,4189 Z M 9200,4357 L 9227,4357 9254,4357 9254,4462 9227,4462 9200,4462 9200,4357 Z M 9200,4525 L 9227,4525 9254,4525 9254,4630 9227,4630 9200,4630 9200,4525 Z M 9200,4693 L 9227,4693 9254,4693 9254,4798 9227,4798 9200,4798 9200,4693 Z M 9200,4861 L 9227,4861 9254,4861 9254,4966 9227,4966 9200,4966 9200,4861 Z M 9200,5029 L 9227,5029 9254,5029 9254,5134 9227,5134 9200,5134 9200,5029 Z M 9200,5197 L 9227,5197 9254,5197 9254,5302 9227,5302 9200,5302 9200,5197 Z M 9200,5365 L 9227,5365 9254,5365 9254,5470 9227,5470 9200,5470 9200,5365 Z M 9200,5533 L 9227,5533 9254,5533 9254,5638 9227,5638 9200,5638 9200,5533 Z M 9200,5701 L 9227,5701 9254,5701 9254,5806 9227,5806 9200,5806 9200,5701 Z M 9200,5869 L 9227,5869 9254,5869 9254,5974 9227,5974 9200,5974 9200,5869 Z M 9200,6037 L 9227,6037 9254,6037 9254,6142 9227,6142 9200,6142 9200,6037 Z M 9200,6205 L 9227,6205 9254,6205 9254,6310 9227,6310 9200,6310 9200,6205 Z M 9200,6373 L 9227,6373 9254,6373 9254,6478 9227,6478 9200,6478 9200,6373 Z M 9200,6541 L 9227,6541 9254,6541 9254,6646 9227,6646 9200,6646 9200,6541 Z M 9200,6709 L 9227,6709 9254,6709 9254,6814 9227,6814 9200,6814 9200,6709 Z M 9200,6877 L 9227,6877 9254,6877 9254,6982 9227,6982 9200,6982 9200,6877 Z M 9200,7045 L 9227,7045 9254,7045 9254,7150 9227,7150 9200,7150 9200,7045 Z M 9200,7213 L 9227,7213 9254,7213 9254,7318 9227,7318 9200,7318 9200,7213 Z M 9200,7381 L 9227,7381 9254,7381 9254,7486 9227,7486 9200,7486 9200,7381 Z M 9200,7549 L 9227,7549 9254,7549 9254,7654 9227,7654 9200,7654 9200,7549 Z M 9200,7717 L 9227,7717 9254,7717 9254,7822 9227,7822 9200,7822 9200,7717 Z M 9200,7886 L 9227,7886 9254,7886 9254,7990 9227,7990 9200,7990 9200,7886 Z M 9200,8054 L 9227,8054 9254,8054 9254,8158 9227,8158 9200,8158 9200,8054 Z M 9200,8222 L 9227,8222 9254,8222 9254,8326 9227,8326 9200,8326 9200,8222 Z M 9200,8390 L 9227,8390 9254,8390 9254,8494 9227,8494 9200,8494 9200,8390 Z M 9200,8558 L 9227,8558 9254,8558 9254,8662 9227,8662 9200,8662 9200,8558 Z M 9200,8726 L 9227,8726 9254,8726 9254,8830 9227,8830 9200,8830 9200,8726 Z M 9200,8894 L 9227,8894 9254,8894 9254,8998 9227,8998 9200,8998 9200,8894 Z M 9200,9062 L 9227,9062 9254,9062 9254,9166 9227,9166 9200,9166 9200,9062 Z M 9200,9230 L 9227,9230 9254,9230 9254,9334 9227,9334 9200,9334 9200,9230 Z M 9200,9398 L 9227,9398 9254,9398 9254,9502 9227,9502 9200,9502 9200,9398 Z M 9200,9566 L 9227,9566 9254,9566 9254,9670 9227,9670 9200,9670 9200,9566 Z M 9200,9734 L 9227,9734 9254,9734 9254,9838 9227,9838 9200,9838 9200,9734 Z M 9200,9902 L 9227,9902 9254,9902 9254,10006 9227,10006 9200,10006 9200,9902 Z M 9200,10070 L 9227,10070 9254,10070 9254,10174 9227,10174 9200,10174 9200,10070 Z M 9200,10238 L 9227,10238 9254,10238 9254,10342 9227,10342 9200,10342 9200,10238 Z M 9200,10406 L 9227,10406 9254,10406 9254,10510 9227,10510 9200,10510 9200,10406 Z M 9200,10574 L 9227,10574 9254,10574 9254,10678 9227,10678 9200,10678 9200,10574 Z M 9200,10742 L 9227,10742 9254,10742 9254,10846 9227,10846 9200,10846 9200,10742 Z M 9200,10910 L 9227,10910 9254,10910 9254,11014 9227,11014 9200,11014 9200,10910 Z M 9200,11078 L 9227,11078 9254,11078 9254,11160 C 9254,11165 9253,11169 9251,11173 9248,11177 9245,11181 9241,11183 9237,11185 9232,11186 9227,11186 L 9204,11186 9204,11160 9200,11160 9200,11078 Z M 9139,11134 L 9139,11160 9139,11186 9032,11186 9032,11160 9032,11134 9139,11134 Z M 8966,11134 L 8966,11160 8966,11186 8859,11186 8859,11160 8859,11134 8966,11134 Z M 8793,11134 L 8793,11160 8793,11186 8686,11186 8686,11160 8686,11134 8793,11134 Z M 8620,11134 L 8620,11160 8620,11186 8513,11186 8513,11160 8513,11134 8620,11134 Z M 8447,11134 L 8447,11160 8447,11186 8340,11186 8340,11160 8340,11134 8447,11134 Z M 8274,11134 L 8274,11160 8274,11186 8167,11186 8167,11160 8167,11134 8274,11134 Z M 8102,11134 L 8102,11160 8102,11186 7994,11186 7994,11160 7994,11134 8102,11134 Z M 7929,11134 L 7929,11160 7929,11186 7821,11186 7821,11160 7821,11134 7929,11134 Z M 7756,11134 L 7756,11160 7756,11186 7648,11186 7648,11160 7648,11134 7756,11134 Z M 7583,11134 L 7583,11160 7583,11186 7475,11186 7475,11160 7475,11134 7583,11134 Z M 7410,11134 L 7410,11160 7410,11186 7302,11186 7302,11160 7302,11134 7410,11134 Z M 7237,11134 L 7237,11160 7237,11186 7130,11186 7130,11160 7130,11134 7237,11134 Z M 7064,11134 L 7064,11160 7064,11186 6957,11186 6957,11160 6957,11134 7064,11134 Z M 6891,11134 L 6891,11160 6891,11186 6784,11186 6784,11160 6784,11134 6891,11134 Z M 6718,11134 L 6718,11160 6718,11186 6611,11186 6611,11160 6611,11134 6718,11134 Z M 6545,11134 L 6545,11160 6545,11186 6438,11186 6438,11160 6438,11134 6545,11134 Z M 6373,11134 L 6373,11160 6373,11186 6265,11186 6265,11160 6265,11134 6373,11134 Z M 6200,11134 L 6200,11160 6200,11186 6092,11186 6092,11160 6092,11134 6200,11134 Z M 6027,11134 L 6027,11160 6027,11186 5919,11186 5919,11160 5919,11134 6027,11134 Z M 5854,11134 L 5854,11160 5854,11186 5746,11186 5746,11160 5746,11134 5854,11134 Z M 5681,11134 L 5681,11160 5681,11186 5573,11186 5573,11160 5573,11134 5681,11134 Z M 5508,11134 L 5508,11160 5508,11186 5401,11186 5401,11160 5401,11134 5508,11134 Z M 5335,11134 L 5335,11160 5335,11186 5228,11186 5228,11160 5228,11134 5335,11134 Z M 5162,11134 L 5162,11160 5162,11186 5055,11186 5055,11160 5055,11134 5162,11134 Z M 4989,11134 L 4989,11160 4989,11186 4882,11186 4882,11160 4882,11134 4989,11134 Z M 4816,11134 L 4816,11160 4816,11186 4709,11186 4709,11160 4709,11134 4816,11134 Z M 4643,11134 L 4643,11160 4643,11186 4536,11186 4536,11160 4536,11134 4643,11134 Z M 4471,11134 L 4471,11160 4471,11186 4363,11186 4363,11160 4363,11134 4471,11134 Z M 4298,11134 L 4298,11160 4298,11186 4190,11186 4190,11160 4190,11134 4298,11134 Z M 4125,11134 L 4125,11160 4125,11186 4017,11186 4017,11160 4017,11134 4125,11134 Z M 3952,11134 L 3952,11160 3952,11186 3844,11186 3844,11160 3844,11134 3952,11134 Z M 3779,11134 L 3779,11160 3779,11186 3671,11186 3671,11160 3671,11134 3779,11134 Z M 3606,11134 L 3606,11160 3606,11186 3499,11186 3499,11160 3499,11134 3606,11134 Z M 3433,11134 L 3433,11160 3433,11186 3326,11186 3326,11160 3326,11134 3433,11134 Z M 3260,11134 L 3260,11160 3260,11186 3153,11186 3153,11160 3153,11134 3260,11134 Z M 3087,11134 L 3087,11160 3087,11186 2980,11186 2980,11160 2980,11134 3087,11134 Z M 2914,11134 L 2914,11160 2914,11186 2807,11186 2807,11160 2807,11134 2914,11134 Z M 2741,11134 L 2741,11160 2741,11186 2634,11186 2634,11160 2634,11134 2741,11134 Z M 2569,11134 L 2569,11160 2569,11186 2461,11186 2461,11160 2461,11134 2569,11134 Z"/> + </g> + </g> + <g class="com.sun.star.drawing.CustomShape"> + <g id="id14"> + <rect class="BoundingBox" stroke="none" fill="none" x="7086" y="3539" width="4194" height="1273"/> + <path fill="rgb(114,159,207)" stroke="none" d="M 9183,4810 L 7087,4810 7087,3540 11278,3540 11278,4810 9183,4810 Z"/> + <path fill="none" stroke="rgb(52,101,164)" d="M 9183,4810 L 7087,4810 7087,3540 11278,3540 11278,4810 9183,4810 Z"/> + <text class="TextShape"><tspan class="TextParagraph" font-family="Liberation Sans, sans-serif" font-size="459px" font-weight="400"><tspan class="TextPosition" x="8218" y="4078"><tspan fill="rgb(0,0,0)" stroke="none">PCEPLIB</tspan></tspan></tspan><tspan class="TextParagraph" font-family="Liberation Sans, sans-serif" font-size="459px" font-weight="400"><tspan class="TextPosition" x="7900" y="4590"><tspan fill="rgb(0,0,0)" stroke="none">INTERFACE</tspan></tspan></tspan></text> + </g> + </g> + <g class="com.sun.star.drawing.LineShape"> + <g id="id15"> + <rect class="BoundingBox" stroke="none" fill="none" x="1665" y="6105" width="2033" height="205"/> + <path fill="none" stroke="rgb(102,102,102)" stroke-width="35" stroke-linejoin="round" d="M 1956,6207 L 3406,6207"/> + <path fill="rgb(102,102,102)" stroke="none" d="M 1665,6207 L 1970,6309 1970,6106 1665,6207 Z"/> + <path fill="rgb(102,102,102)" stroke="none" d="M 3697,6207 L 3393,6106 3393,6309 3697,6207 Z"/> + </g> + </g> + <g class="com.sun.star.drawing.LineShape"> + <g id="id16"> + <rect class="BoundingBox" stroke="none" fill="none" x="1665" y="5470" width="2033" height="205"/> + <path fill="none" stroke="rgb(102,102,102)" stroke-width="35" stroke-linejoin="round" d="M 1956,5572 L 3406,5572"/> + <path fill="rgb(102,102,102)" stroke="none" d="M 1665,5572 L 1970,5674 1970,5471 1665,5572 Z"/> + <path fill="rgb(102,102,102)" stroke="none" d="M 3697,5572 L 3393,5471 3393,5674 3697,5572 Z"/> + </g> + </g> + <g class="com.sun.star.drawing.CustomShape"> + <g id="id17"> + <rect class="BoundingBox" stroke="none" fill="none" x="4584" y="9553" width="9528" height="1146"/> + <path fill="rgb(114,159,207)" stroke="none" d="M 9348,10697 L 4585,10697 4585,9554 14110,9554 14110,10697 9348,10697 Z"/> + <path fill="none" stroke="rgb(52,101,164)" d="M 9348,10697 L 4585,10697 4585,9554 14110,9554 14110,10697 9348,10697 Z"/> + <text class="TextShape"><tspan class="TextParagraph" font-family="Liberation Sans, sans-serif" font-size="459px" font-weight="400"><tspan class="TextPosition" x="7786" y="10285"><tspan fill="rgb(0,0,0)" stroke="none">CONTROLLER</tspan></tspan></tspan></text> + </g> + </g> + <g class="com.sun.star.drawing.TextShape"> + <g id="id18"> + <rect class="BoundingBox" stroke="none" fill="none" x="6491" y="9448" width="2383" height="570"/> + <text class="TextShape"><tspan class="TextParagraph" font-family="Liberation Sans, sans-serif" font-size="282px" font-weight="400"><tspan class="TextPosition" x="6741" y="9831"><tspan fill="rgb(0,0,0)" stroke="none">pcep_ctrl_XXX</tspan></tspan></tspan></text> + </g> + </g> + <g class="com.sun.star.drawing.TextShape"> + <g id="id19"> + <rect class="BoundingBox" stroke="none" fill="none" x="9920" y="9448" width="2802" height="570"/> + <text class="TextShape"><tspan class="TextParagraph" font-family="Liberation Sans, sans-serif" font-size="282px" font-weight="400"><tspan class="TextPosition" x="10170" y="9831"><tspan fill="rgb(0,0,0)" stroke="none">pcep_thread_XXX</tspan></tspan></tspan></text> + </g> + </g> + <g class="com.sun.star.drawing.LineShape"> + <g id="id20"> + <rect class="BoundingBox" stroke="none" fill="none" x="5953" y="8366" width="1682" height="1271"/> + <path fill="none" stroke="rgb(102,102,102)" stroke-width="35" stroke-linejoin="round" d="M 6185,8541 L 7402,9461"/> + <path fill="rgb(102,102,102)" stroke="none" d="M 5953,8366 L 6135,8631 6257,8469 5953,8366 Z"/> + <path fill="rgb(102,102,102)" stroke="none" d="M 7634,9636 L 7452,9371 7330,9533 7634,9636 Z"/> + </g> + </g> + <g class="com.sun.star.drawing.LineShape"> + <g id="id21"> + <rect class="BoundingBox" stroke="none" fill="none" x="5953" y="6207" width="2287" height="3430"/> + <path fill="none" stroke="rgb(102,102,102)" stroke-width="35" stroke-linejoin="round" d="M 6114,6449 L 8078,9394"/> + <path fill="rgb(102,102,102)" stroke="none" d="M 5953,6207 L 6037,6517 6206,6404 5953,6207 Z"/> + <path fill="rgb(102,102,102)" stroke="none" d="M 8239,9636 L 8155,9326 7986,9439 8239,9636 Z"/> + </g> + </g> + <g class="com.sun.star.drawing.LineShape"> + <g id="id22"> + <rect class="BoundingBox" stroke="none" fill="none" x="5953" y="4683" width="1652" height="763"/> + <path fill="none" stroke="rgb(102,102,102)" stroke-width="35" stroke-linejoin="round" d="M 6217,5323 L 7340,4805"/> + <path fill="rgb(102,102,102)" stroke="none" d="M 5953,5445 L 6272,5410 6187,5225 5953,5445 Z"/> + <path fill="rgb(102,102,102)" stroke="none" d="M 7604,4683 L 7285,4718 7370,4903 7604,4683 Z"/> + </g> + </g> + <g class="com.sun.star.drawing.LineShape"> + <g id="id23"> + <rect class="BoundingBox" stroke="none" fill="none" x="5953" y="4683" width="2287" height="3049"/> + <path fill="none" stroke="rgb(102,102,102)" stroke-width="35" stroke-linejoin="round" d="M 6128,7498 L 8064,4916"/> + <path fill="rgb(102,102,102)" stroke="none" d="M 5953,7731 L 6217,7548 6054,7427 5953,7731 Z"/> + <path fill="rgb(102,102,102)" stroke="none" d="M 8239,4683 L 7975,4866 8138,4988 8239,4683 Z"/> + </g> + </g> + <g class="com.sun.star.drawing.LineShape"> + <g id="id24"> + <rect class="BoundingBox" stroke="none" fill="none" x="8772" y="1635" width="205" height="2033"/> + <path fill="none" stroke="rgb(102,102,102)" stroke-width="35" stroke-linejoin="round" d="M 8874,3376 L 8874,1926"/> + <path fill="rgb(102,102,102)" stroke="none" d="M 8874,3667 L 8976,3363 8773,3363 8874,3667 Z"/> + <path fill="rgb(102,102,102)" stroke="none" d="M 8874,1635 L 8773,1940 8976,1940 8874,1635 Z"/> + </g> + </g> + <g class="com.sun.star.drawing.TextShape"> + <g id="id25"> + <rect class="BoundingBox" stroke="none" fill="none" x="8347" y="1127" width="1925" height="570"/> + <text class="TextShape"><tspan class="TextParagraph" font-family="Liberation Sans, sans-serif" font-size="282px" font-weight="400"><tspan class="TextPosition" x="8597" y="1510"><tspan fill="rgb(0,0,0)" stroke="none">pceplib API</tspan></tspan></tspan></text> + </g> + </g> + <g class="com.sun.star.drawing.LineShape"> + <g id="id26"> + <rect class="BoundingBox" stroke="none" fill="none" x="11033" y="4683" width="1779" height="1525"/> + <path fill="none" stroke="rgb(102,102,102)" stroke-width="35" stroke-linejoin="round" d="M 11254,4872 L 12590,6018"/> + <path fill="rgb(102,102,102)" stroke="none" d="M 11033,4683 L 11198,4958 11330,4804 11033,4683 Z"/> + <path fill="rgb(102,102,102)" stroke="none" d="M 12811,6207 L 12646,5932 12514,6086 12811,6207 Z"/> + </g> + </g> + <g class="com.sun.star.drawing.LineShape"> + <g id="id27"> + <rect class="BoundingBox" stroke="none" fill="none" x="11063" y="7223" width="1749" height="2414"/> + <path fill="none" stroke="rgb(102,102,102)" stroke-width="35" stroke-linejoin="round" d="M 11234,9400 L 12640,7459"/> + <path fill="rgb(102,102,102)" stroke="none" d="M 11063,9636 L 11324,9449 11159,9330 11063,9636 Z"/> + <path fill="rgb(102,102,102)" stroke="none" d="M 12811,7223 L 12550,7410 12715,7529 12811,7223 Z"/> + </g> + </g> + <g class="com.sun.star.drawing.LineShape"> + <g id="id28"> + <rect class="BoundingBox" stroke="none" fill="none" x="9534" y="1635" width="205" height="2033"/> + <path fill="none" stroke="rgb(102,102,102)" stroke-width="35" stroke-linejoin="round" d="M 9636,3376 L 9636,1926"/> + <path fill="rgb(102,102,102)" stroke="none" d="M 9636,3667 L 9738,3363 9535,3363 9636,3667 Z"/> + <path fill="rgb(102,102,102)" stroke="none" d="M 9636,1635 L 9535,1940 9738,1940 9636,1635 Z"/> + </g> + </g> + </g> + </g> + </g> + </g> + </g> +</svg>
\ No newline at end of file diff --git a/doc/user/bgp.rst b/doc/user/bgp.rst index c65f1144eb..cb97ee22df 100644 --- a/doc/user/bgp.rst +++ b/doc/user/bgp.rst @@ -31,12 +31,23 @@ be specified (:ref:`common-invocation-options`). .. option:: -l, --listenon - Specify a specific IP address for bgpd to listen on, rather than its default + Specify specific IP addresses for bgpd to listen on, rather than its default of ``0.0.0.0`` / ``::``. This can be useful to constrain bgpd to an internal - address, or to run multiple bgpd processes on one host. + address, or to run multiple bgpd processes on one host. Multiple addresses + can be specified. + + In the following example, bgpd is started listening for connections on the + addresses 100.0.1.2 and fd00::2:2. The options -d (runs in daemon mode) and + -f (uses specific configuration file) are also used in this example as we + are likely to run multiple bgpd instances, each one with different + configurations, when using -l option. Note that this option implies the --no_kernel option, and no learned routes will be installed into the linux kernel. +.. code-block:: shell + + # /usr/lib/frr/bgpd -d -f /some-folder/bgpd.conf -l 100.0.1.2 -l fd00::2:2 + .. option:: -n, --no_kernel Do not install learned routes into the linux kernel. This option is useful @@ -424,10 +435,14 @@ Require policy on EBGP .. clicmd:: [no] bgp ebgp-requires-policy This command requires incoming and outgoing filters to be applied - for eBGP sessions. Without the incoming filter, no routes will be - accepted. Without the outgoing filter, no routes will be announced. + for eBGP sessions as part of RFC-8212 compliance. Without the incoming + filter, no routes will be accepted. Without the outgoing filter, no + routes will be announced. - This is enabled by default. + This is enabled by default for the traditional configuration and + turned off by default for datacenter configuration. + + When you enable/disable this option you MUST clear the session. When the incoming or outgoing filter is missing you will see "(Policy)" sign under ``show bgp summary``: @@ -446,6 +461,22 @@ Require policy on EBGP 192.168.0.2 4 65002 8 10 0 0 0 00:03:09 5 (Policy) fe80:1::2222 4 65002 9 11 0 0 0 00:03:09 (Policy) (Policy) + Additionally a `show bgp neighbor` command would indicate in the `For address family:` + block that: + + .. code-block:: frr + + exit1# show bgp neighbor + ... + For address family: IPv4 Unicast + Update group 1, subgroup 1 + Packet Queue length 0 + Inbound soft reconfiguration allowed + Community attribute sent to this neighbor(all) + Inbound updates discarded due to missing policy + Outbound updates discarded due to missing policy + 0 accepted prefixes + Reject routes with AS_SET or AS_CONFED_SET types ------------------------------------------------ @@ -454,6 +485,17 @@ Reject routes with AS_SET or AS_CONFED_SET types This command enables rejection of incoming and outgoing routes having AS_SET or AS_CONFED_SET type. +Suppress duplicate updates +-------------------------- + +.. index:: bgp suppress-duplicates +.. clicmd:: [no] bgp suppress-duplicates + + For example, BGP routers can generate multiple identical announcements with + empty community attributes if stripped at egress. This is an undesired behavior. + Suppress duplicate updates if the route actually not changed. + Default: enabled. + Disable checking if nexthop is connected on EBGP sessions --------------------------------------------------------- @@ -469,28 +511,57 @@ Disable checking if nexthop is connected on EBGP sessions Route Flap Dampening -------------------- -.. clicmd:: bgp dampening (1-45) (1-20000) (1-20000) (1-255) +.. index:: [no] bgp dampening [(1-45) [(1-20000) (1-20000) (1-255)]] +.. clicmd:: [no] bgp dampening [(1-45) [(1-20000) (1-20000) (1-255)]] + + This command enables (with optionally specified dampening parameters) or + disables route-flap dampening for all routes of a BGP instance. - This command enables BGP route-flap dampening and specifies dampening parameters. +.. index:: [no] neighbor PEER dampening [(1-45) [(1-20000) (1-20000) (1-255)]] +.. clicmd:: [no] neighbor PEER dampening [(1-45) [(1-20000) (1-20000) (1-255)]] + + This command enables (with optionally specified dampening parameters) or + disables route-flap dampening for all routes learned from a BGP peer. + +.. index:: [no] neighbor GROUP dampening [(1-45) [(1-20000) (1-20000) (1-255)]] +.. clicmd:: [no] neighbor GROUP dampening [(1-45) [(1-20000) (1-20000) (1-255)]] + + This command enables (with optionally specified dampening parameters) or + disables route-flap dampening for all routes learned from peers of a peer + group. half-life - Half-life time for the penalty + Half-life time for the penalty in minutes (default value: 15). reuse-threshold - Value to start reusing a route + Value to start reusing a route (default value: 750). suppress-threshold - Value to start suppressing a route + Value to start suppressing a route (default value: 2000). max-suppress - Maximum duration to suppress a stable route + Maximum duration to suppress a stable route in minutes (default value: + 60). The route-flap damping algorithm is compatible with :rfc:`2439`. The use of - this command is not recommended nowadays. + these commands is not recommended nowadays. At the moment, route-flap dampening is not working per VRF and is working only for IPv4 unicast and multicast. + With different parameter sets configurable for BGP instances, peer groups and + peers, the active dampening profile for a route is chosen on the fly, + allowing for various changes in configuration (i.e. peer group memberships) + during runtime. The parameter sets are taking precedence in the following + order: + + 1. Peer + 2. Peer group + 3. BGP instance + + The negating commands do not allow to exclude a peer/peer group from a peer + group/BGP instances configuration. + .. seealso:: https://www.ripe.net/publications/docs/ripe-378 @@ -798,6 +869,38 @@ The following functionality is provided by graceful restart: <---------------------------------------------------------------------> +.. _bgp-GR-preserve-forwarding-state: + +BGP-GR Preserve-Forwarding State +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +BGP OPEN message carrying optional capabilities for Graceful Restart has +8 bit “Flags for Address Family” for given AFI and SAFI. This field contains +bit flags relating to routes that were advertised with the given AFI and SAFI. + +.. code-block:: frr + + 0 1 2 3 4 5 6 7 + +-+-+-+-+-+-+-+-+ + |F| Reserved | + +-+-+-+-+-+-+-+-+ + +The most significant bit is defined as the Forwarding State (F) bit, which +can be used to indicate whether the forwarding state for routes that were +advertised with the given AFI and SAFI has indeed been preserved during the +previous BGP restart. When set (value 1), the bit indicates that the +forwarding state has been preserved. +The remaining bits are reserved and MUST be set to zero by the sender and +ignored by the receiver. + +.. index:: bgp graceful-restart preserve-fw-state +.. clicmd:: bgp graceful-restart preserve-fw-state + +FRR gives us the option to enable/disable the "F" flag using this specific +vty command. However, it doesn't have the option to enable/disable +this flag only for specific AFI/SAFI i.e. when this command is used, it +applied to all the supported AFI/SAFI combinations for this peer. + .. _bgp-end-of-rib-message: End-of-RIB (EOR) message @@ -851,6 +954,19 @@ However, it MUST defer route selection for an address family until it either. This is command, will set the time for which stale routes are kept in RIB. +.. index:: bgp graceful-restart stalepath-time (1-4095) +.. clicmd:: bgp graceful-restart stalepath-time (1-4095) + + This is command, will set the max time (in seconds) to hold onto + restarting peer's stale paths. + + It also controls Enhanced Route-Refresh timer. + + If this command is configured and the router does not receive a Route-Refresh EoRR + message, the router removes the stale routes from the BGP table after the timer + expires. The stale path timer is started when the router receives a Route-Refresh + BoRR message. + .. _bgp-per-peer-graceful-restart: BGP Per Peer Graceful Restart @@ -1372,6 +1488,9 @@ Configuring Peers directly connected and this knob is not enabled, the session will not establish. + If the peer's IP address is not in the RIB and is reachable via the + default route, then you have to enable ``ip nht resolve-via-default``. + .. index:: neighbor PEER description ... .. clicmd:: [no] neighbor PEER description ... @@ -1596,7 +1715,7 @@ Configuring Peers peer in question. This number is between 0 and 600 seconds, with the default advertisement interval being 0. -.. index:: [no] neighbor PEER timers delayopen (1-240) +.. index:: neighbor PEER timers delayopen (1-240) .. clicmd:: [no] neighbor PEER timers delayopen (1-240) This command allows the user enable the @@ -1871,9 +1990,9 @@ is 4 octet long. The following format is used to define the community value. ``0xFFFF029A`` ``65535:666``. :rfc:`7999` documents sending prefixes to EBGP peers and upstream for the purpose of blackholing traffic. Prefixes tagged with the this community should normally not be - re-advertised from neighbors of the originating network. It is - recommended upon receiving prefixes tagged with this community to - add ``NO_EXPORT`` and ``NO_ADVERTISE``. + re-advertised from neighbors of the originating network. Upon receiving + ``BLACKHOLE`` community from a BGP speaker, ``NO_ADVERTISE`` community + is added automatically. ``no-export`` ``no-export`` represents well-known communities value ``NO_EXPORT`` @@ -2644,11 +2763,11 @@ Ethernet Segments An Ethernet Segment can be configured by specifying a system-MAC and a local discriminatior against the bond interface on the PE (via zebra) - -.. index:: evpn mh es-id [(1-16777215)$es_lid] -.. clicmd:: [no] evpn mh es-id [(1-16777215)$es_lid] +.. index:: evpn mh es-id (1-16777215) +.. clicmd:: [no] evpn mh es-id (1-16777215) -.. index:: evpn mh es-sys-mac [X:X:X:X:X:X$mac] -.. clicmd:: [no$no] evpn mh es-sys-mac [X:X:X:X:X:X$mac] +.. index:: evpn mh es-sys-mac X:X:X:X:X:X +.. clicmd:: [no] evpn mh es-sys-mac X:X:X:X:X:X The sys-mac and local discriminator are used for generating a 10-byte, Type-3 Ethernet Segment ID. @@ -2671,8 +2790,8 @@ forward BUM traffic received via the overlay network. This implementation uses a preference based DF election specified by draft-ietf-bess-evpn-pref-df. The DF preference is configurable per-ES (via zebra) - -.. index:: evpn mh es-df-pref [(1-16777215)$df_pref] -.. clicmd:: [no] evpn mh es-df-pref [(1-16777215)$df_pref] +.. index:: evpn mh es-df-pref (1-16777215) +.. clicmd:: [no] evpn mh es-df-pref (1-16777215) BUM traffic is rxed via the overlay by all PEs attached to a server but only the DF can forward the de-capsulated traffic to the access port. To @@ -2682,6 +2801,20 @@ the traffic. Similarly traffic received from ES peers via the overlay cannot be forwarded to the server. This is split-horizon-filtering with local bias. +Knobs for interop +""""""""""""""""" +Some vendors do not send EAD-per-EVI routes. To interop with them we +need to relax the dependency on EAD-per-EVI routes and activate a remote +ES-PE based on just the EAD-per-ES route. + +Note that by default we advertise and expect EAD-per-EVI routes. + +.. index:: disable-ead-evi-rx +.. clicmd:: [no] disable-ead-evi-rx + +.. index:: disable-ead-evi-tx +.. clicmd:: [no] disable-ead-evi-tx + Fast failover """"""""""""" As the primary purpose of EVPN-MH is redundancy keeping the failover efficient @@ -2695,14 +2828,14 @@ been introduced for the express purpose of efficient ES failovers. on via the following BGP config - .. index:: use-es-l3nhg -.. clicmd:: [no$no] use-es-l3nhg +.. clicmd:: [no] use-es-l3nhg - Local ES (MAC/Neigh) failover via ES-redirect. On dataplanes that do not have support for ES-redirect the feature can be turned off via the following zebra config - .. index:: evpn mh redirect-off -.. clicmd:: [no$no] evpn mh redirect-off +.. clicmd:: [no] evpn mh redirect-off Uplink/Core tracking """""""""""""""""""" @@ -2723,11 +2856,11 @@ the ES peer (PE2) goes down PE1 continues to advertise hosts learnt from PE2 for a holdtime during which it attempts to establish local reachability of the host. This holdtime is configurable via the following zebra commands - -.. index:: evpn mh neigh-holdtime (0-86400)$duration -.. clicmd:: [no$no] evpn mh neigh-holdtime (0-86400)$duration +.. index:: evpn mh neigh-holdtime (0-86400) +.. clicmd:: [no] evpn mh neigh-holdtime (0-86400) -.. index:: evpn mh mac-holdtime (0-86400)$duration -.. clicmd:: [no$no] evpn mh mac-holdtime (0-86400)$duration +.. index:: evpn mh mac-holdtime (0-86400) +.. clicmd:: [no] evpn mh mac-holdtime (0-86400) Startup delay """"""""""""" @@ -2736,8 +2869,8 @@ and EVPN network to converge before enabling the ESs. For this duration the ES bonds are held protodown. The startup delay is configurable via the following zebra command - -.. index:: evpn mh startup-delay(0-3600)$duration -.. clicmd:: [no] evpn mh startup-delay(0-3600)$duration +.. index:: evpn mh startup-delay (0-3600) +.. clicmd:: [no] evpn mh startup-delay (0-3600) +Support with VRF network namespace backend +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -3199,8 +3332,8 @@ Some other commands provide additional options for filtering the output. This command displays BGP routes using AS path regular expression (:ref:`bgp-regular-expressions`). -.. index:: show [ip] bgp [all] summary [json] -.. clicmd:: show [ip] bgp [all] summary [json] +.. index:: show [ip] bgp [all] summary [wide] [json] +.. clicmd:: show [ip] bgp [all] summary [wide] [json] Show a bgp peer summary for the specified address family. @@ -3209,6 +3342,25 @@ and should no longer be used. In order to reach the other BGP routing tables other than the IPv6 routing table given by :clicmd:`show bgp`, the new command structure is extended with :clicmd:`show bgp [afi] [safi]`. +``wide`` option gives more output like ``LocalAS`` and extended ``Desc`` to +64 characters. + + .. code-block:: frr + + exit1# show ip bgp summary wide + + IPv4 Unicast Summary: + BGP router identifier 192.168.100.1, local AS number 65534 vrf-id 0 + BGP table version 3 + RIB entries 5, using 920 bytes of memory + Peers 1, using 27 KiB of memory + + Neighbor V AS LocalAS MsgRcvd MsgSent TblVer InQ OutQ Up/Down State/PfxRcd PfxSnt Desc + 192.168.0.2 4 65030 123 15 22 0 0 0 00:07:00 0 1 us-east1-rs1.frrouting.org + + Total number of neighbors 1 + exit1# + .. index:: show bgp [afi] [safi] [all] [wide|json] .. clicmd:: show bgp [afi] [safi] [all] [wide|json] @@ -3341,6 +3493,32 @@ attribute. If ``json`` option is specified, output is displayed in JSON format. +.. index:: show bgp labelpool <chunks|inuse|ledger|requests|summary> [json] +.. clicmd:: show bgp labelpool <chunks|inuse|ledger|requests|summary> [json] + + These commands display information about the BGP labelpool used for + the association of MPLS labels with routes for L3VPN and Labeled Unicast + + If ``chunks`` option is specified, output shows the current list of label + chunks granted to BGP by Zebra, indicating the start and end label in + each chunk + + If ``inuse`` option is specified, output shows the current inuse list of + label to prefix mappings + + If ``ledger`` option is specified, output shows ledger list of all + label requests made per prefix + + If ``requests`` option is specified, output shows current list of label + requests which have not yet been fulfilled by the labelpool + + If ``summary`` option is specified, output is a summary of the counts for + the chunks, inuse, ledger and requests list along with the count of + outstanding chunk requests to Zebra and the nummber of zebra reconnects + that have happened + + If ``json`` option is specified, output is displayed in JSON format. + .. _bgp-display-routes-by-lcommunity: Displaying Routes by Large Community Attribute @@ -3470,10 +3648,10 @@ starting the daemon and the configuration gets saved, the option will persist unless removed from the configuration with the negating command prior to the configuration write operation. -.. index:: [no] bgp send-extra-data zebra +.. index:: bgp send-extra-data zebra .. clicmd:: [no] bgp send-extra-data zebra - This Command turns off the ability of BGP to send extra data to zebra. +This Command turns off the ability of BGP to send extra data to zebra. In this case it's the AS-Path being used for the path. The default behavior in BGP is to send this data and to turn it off enter the no form of the command. If extra data was sent to zebra, and this command is turned on there is no diff --git a/doc/user/fabricd.rst b/doc/user/fabricd.rst index a74d3e098b..17a51ccb3c 100644 --- a/doc/user/fabricd.rst +++ b/doc/user/fabricd.rst @@ -57,6 +57,19 @@ in the configuration: Configure the authentication password for a domain, as clear text or md5 one. +.. index:: attached-bit [receive ignore | send] +.. clicmd:: attached-bit [receive ignore | send] + +.. index:: attached-bit +.. clicmd:: no attached-bit + + Set attached bit for inter-area traffic: + + - receive + If LSP received with attached bit set, create default route to neighbor + - send + If L1|L2 router, set attached bit in LSP sent to L1 router + .. index:: log-adjacency-changes .. clicmd:: log-adjacency-changes @@ -64,7 +77,7 @@ in the configuration: .. clicmd:: no log-adjacency-changes Log changes in adjacency state. - + .. index:: set-overload-bit .. clicmd:: set-overload-bit diff --git a/doc/user/index.rst b/doc/user/index.rst index 8ac997f8dd..7b9464668b 100644 --- a/doc/user/index.rst +++ b/doc/user/index.rst @@ -29,6 +29,7 @@ Basics ipv6 kernel snmp + scripting .. modules ######### @@ -50,6 +51,7 @@ Protocols nhrpd ospfd ospf6d + pathd pim pbr ripd diff --git a/doc/user/installation.rst b/doc/user/installation.rst index 382d71b71f..a13e6ce43b 100644 --- a/doc/user/installation.rst +++ b/doc/user/installation.rst @@ -362,6 +362,10 @@ options from the list below. Set hardcoded rpaths in the executable [default=yes]. +.. option:: --enable-scripting + + Enable Lua scripting [default=no]. + You may specify any combination of the above options to the configure script. By default, the executables are placed in :file:`/usr/local/sbin` and the configuration files in :file:`/usr/local/etc`. The :file:`/usr/local/` @@ -382,6 +386,10 @@ options to the configuration script. Configure zebra to use `dir` for local state files, such as pid files and unix sockets. +.. option:: --with-scriptdir <dir> + + Look for Lua scripts in ``dir`` [``prefix``/etc/frr/scripts]. + .. option:: --with-yangmodelsdir <dir> Look for YANG modules in `dir` [`prefix`/share/yang]. Note that the FRR diff --git a/doc/user/isisd.rst b/doc/user/isisd.rst index f991e3f073..352701728d 100644 --- a/doc/user/isisd.rst +++ b/doc/user/isisd.rst @@ -72,6 +72,19 @@ writing, *isisd* does not support multiple ISIS processes. Configure the authentication password for an area, respectively a domain, as clear text or md5 one. +.. index:: attached-bit [receive ignore | send] +.. clicmd:: attached-bit [receive ignore | send] + +.. index:: attached-bit +.. clicmd:: no attached-bit + + Set attached bit for inter-area traffic: + + - receive + If LSP received with attached bit set, create default route to neighbor + - send + If L1|L2 router, set attached bit in LSP sent to L1 router + .. index:: log-adjacency-changes .. clicmd:: log-adjacency-changes @@ -204,6 +217,12 @@ ISIS Fast-Reroute Disable load sharing across multiple LFA backups. +.. index:: fast-reroute remote-lfa prefix-list WORD [level-1 | level-2] +.. clicmd:: [no] fast-reroute remote-lfa prefix-list [WORD] [level-1 | level-2] + + Configure a prefix-list to select eligible PQ nodes (valid for all protected + interfaces). + .. _isis-region: ISIS region @@ -400,6 +419,18 @@ ISIS interface Enable per-prefix TI-LFA fast reroute link or node protection. +.. index:: isis fast-reroute remote-lfa tunnel mpls-ldp [level-1 | level-2] +.. clicmd:: [no] isis fast-reroute remote-lfa tunnel mpls-ldp [level-1 | level-2] + + Enable per-prefix Remote LFA fast reroute link protection. Note that other + routers in the network need to be configured to accept LDP targeted hello + messages in order for RLFA to work. + +.. index:: isis fast-reroute remote-lfa maximum-metric (1-16777215) [level-1 | level-2] +.. clicmd:: [no] isis fast-reroute remote-lfa maximum-metric (1-16777215) [level-1 | level-2] + + Limit Remote LFA PQ node selection within the specified metric. + .. _showing-isis-information: Showing ISIS information diff --git a/doc/user/nhrpd.rst b/doc/user/nhrpd.rst index 9caeb0eedb..65645c519d 100644 --- a/doc/user/nhrpd.rst +++ b/doc/user/nhrpd.rst @@ -180,14 +180,15 @@ Integration with IKE nhrpd needs tight integration with IKE daemon for various reasons. Currently only strongSwan is supported as IKE daemon. -nhrpd connects to strongSwan using VICI protocol based on UNIX socket -(hardcoded now as /var/run/charon.vici). +nhrpd connects to strongSwan using VICI protocol based on UNIX socket which +can be configured using the command below (default to /var/run/charon.vici). strongSwan currently needs few patches applied. Please check out the -https://git.alpinelinux.org/user/tteras/strongswan/log/?h=tteras-release -and -https://git.alpinelinux.org/user/tteras/strongswan/log/?h=tteras -git repositories for the patches. +original patches at: +https://git-old.alpinelinux.org/user/tteras/strongswan/ + +Actively maintained patches are also available at: +https://gitlab.alpinelinux.org/alpine/aports/-/tree/master/main/strongswan .. _nhrp-events: diff --git a/doc/user/ospf6d.rst b/doc/user/ospf6d.rst index 4f0ff90943..99119bb7e5 100644 --- a/doc/user/ospf6d.rst +++ b/doc/user/ospf6d.rst @@ -83,6 +83,12 @@ OSPF6 router This configuration setting MUST be consistent across all routers within the OSPF domain. +.. index:: maximum-paths (1-64) +.. clicmd::[no] maximum-paths (1-64) + + Use this command to control the maximum number of parallel routes that + OSPFv3 can support. The default is 64. + .. _ospf6-area: OSPF6 area @@ -170,10 +176,34 @@ Showing OSPF6 information instance ID, simply type "show ipv6 ospf6 <cr>". JSON output can be obtained by appending 'json' to the end of command. -.. index:: show ipv6 ospf6 database -.. clicmd:: show ipv6 ospf6 database +.. index:: show ipv6 ospf6 database [<detail|dump|internal>] [json] +.. clicmd:: show ipv6 ospf6 database [<detail|dump|internal>] [json] + + This command shows LSAs present in the LSDB. There are three view options. + These options helps in viewing all the parameters of the LSAs. JSON output + can be obtained by appending 'json' to the end of command. JSON option is + not applicable with 'dump' option. + +.. index:: show ipv6 ospf6 database <router|network|inter-prefix|inter-router|as-external|group-membership|type-7|link|intra-prefix> [json] +.. clicmd:: show ipv6 ospf6 database <router|network|inter-prefix|inter-router|as-external|group-membership|type-7|link|intra-prefix> [json] + + These options filters out the LSA based on its type. The three views options + works here as well. JSON output can be obtained by appending 'json' to the + end of command. + +.. index:: show ipv6 ospf6 database adv-router A.B.C.D linkstate-id A.B.C.D [json] +.. clicmd:: show ipv6 ospf6 database adv-router A.B.C.D linkstate-id A.B.C.D [json] + + The LSAs additinally can also be filtered with the linkstate-id and + advertising-router fields. We can use the LSA type filter and views with + this command as well and visa-versa. JSON output can be obtained by + appending 'json' to the end of command. - This command shows LSA database summary. You can specify the type of LSA. +.. index:: show ipv6 ospf6 database self-originated [json] +.. clicmd:: show ipv6 ospf6 database self-originated [json] + + This command is used to filter the LSAs which are originated by the present + router. All the other filters are applicable here as well. .. index:: show ipv6 ospf6 interface [json] .. clicmd:: show ipv6 ospf6 interface [json] @@ -216,6 +246,28 @@ Showing OSPF6 information Shows the routes which are redistributed by the router. JSON output can be obtained by appending 'json' at the end. +.. index:: show ipv6 ospf6 route [<intra-area|inter-area|external-1|external-2|X:X::X:X|X:X::X:X/M|detail|summary>] [json] +.. clicmd:: show ipv6 ospf6 route [<intra-area|inter-area|external-1|external-2|X:X::X:X|X:X::X:X/M|detail|summary>] [json] + + This command displays the ospfv3 routing table as determined by the most + recent SPF calculations. Options are provided to view the different types + of routes. Other than the standard view there are two other options, detail + and summary. JSON output can be obtained by appending 'json' to the end of + command. + +.. index:: show ipv6 ospf6 route X:X::X:X/M match [detail] [json] +.. clicmd:: show ipv6 ospf6 route X:X::X:X/M match [detail] [json] + + The additional match option will match the given address to the destination + of the routes, and return the result accordingly. + +.. index:: show ipv6 ospf6 interface [IFNAME] prefix [detail|<X:X::X:X|X:X::X:X/M> [<match|detail>]] [json] +.. clicmd:: show ipv6 ospf6 interface [IFNAME] prefix [detail|<X:X::X:X|X:X::X:X/M> [<match|detail>]] [json] + + This command shows the prefixes present in the interface routing table. + Interface name can also be given. JSON output can be obtained by appending + 'json' to the end of command. + OSPF6 Configuration Examples ============================ diff --git a/doc/user/ospfd.rst b/doc/user/ospfd.rst index cbde0fd46f..ee02a9dae5 100644 --- a/doc/user/ospfd.rst +++ b/doc/user/ospfd.rst @@ -322,6 +322,23 @@ To start OSPF process you have to specify the OSPF router. This feature is enabled by default. +.. index:: clear ip ospf [(1-65535)] process +.. clicmd:: clear ip ospf [(1-65535)] process + + This command can be used to clear the ospf process data structures. This + will clear the ospf neighborship as well and it will get re-established. + This will clear the LSDB too. This will be helpful when there is a change + in router-id and if user wants the router-id change to take effect, user can + use this cli instead of restarting the ospfd daemon. + +.. index:: clear ip ospf [(1-65535)] neighbor +.. clicmd:: clear ip ospf [(1-65535)] neighbor + + This command can be used to clear the ospf neighbor data structures. This + will clear the ospf neighborship and it will get re-established. This + command can be used when the neighbor state get stuck at some state and + this can be used to recover it from that state. + .. _ospf-area: Areas @@ -1216,6 +1233,20 @@ Summary Route will be originated on-behalf of all matched external LSAs. Show configuration for display all configured summary routes with matching external LSA information. +TI-LFA +====== + +Experimental support for Topology Independent LFA (Loop-Free Alternate), see +for example 'draft-bashandy-rtgwg-segment-routing-ti-lfa-05'. Note that +TI-LFA requires a proper Segment Routing configuration. + +.. index:: fast-reroute ti-lfa [node-protection] +.. clicmd:: fast-reroute ti-lfa [node-protection] + + Configured on the router level. Activates TI-LFA for all interfaces. + + Note that so far only P2P interfaces are supported. + Debugging OSPF ============== diff --git a/doc/user/overview.rst b/doc/user/overview.rst index a2ce67068f..f67698e404 100644 --- a/doc/user/overview.rst +++ b/doc/user/overview.rst @@ -321,6 +321,8 @@ BGP :t:`The Resource Public Key Infrastructure (RPKI) to Router Protocol. R. Bush, R. Austein. January 2013.` - :rfc:`6811` :t:`BGP Prefix Origin Validation. P. Mohapatra, J. Scudder, D. Ward, R. Bush, R. Austein. January 2013.` +- :rfc:`7313` + :t:`Enhanced Route Refresh Capability for BGP-4. K. Patel, E. Chen, B. Venkatachalapathy. July 2014.` - :rfc:`7606` :t:`Revised Error Handling for BGP UPDATE Messages. E. Chen, J. Scudder, P. Mohapatra, K. Patel. August 2015.` - :rfc:`7607` diff --git a/doc/user/pathd.rst b/doc/user/pathd.rst new file mode 100644 index 0000000000..0815a6c414 --- /dev/null +++ b/doc/user/pathd.rst @@ -0,0 +1,443 @@ +.. _path: + +**** +PATH +**** + +:abbr:`PATH` is a daemon that handles the installation and deletion +of Segment Routing (SR) Policies. + + +.. _starting-path: + +Starting PATH +============= + +Default configuration file for *pathd* is :file:`pathd.conf`. The typical +location of :file:`pathd.conf` is |INSTALL_PREFIX_ETC|/pathd.conf. + +If the user is using integrated config, then :file:`pathd.conf` need not be +present and the :file:`frr.conf` is read instead. + +.. program:: pathd + +:abbr:`PATH` supports all the common FRR daemon start options which are +documented elsewhere. + + +PCEP Support +============ + +To build the PCC for pathd, the externall library `pceplib 1.2 <https://github.com/volta-networks/pceplib/tree/devel-1.2>`_ is required. + +To build FRR with support for PCEP the following steps must be followed: + + - Checkout and build pceplib: + +``` +$ git clone https://github.com/volta-networks/pceplib +$ cd pceplib +$ make +$ make install +$ export PCEPLIB_ROOT=$PWD +``` + + - Configure FRR with the extra parameters: + +``` +--enable-pcep LDFLAGS="-L${PCEPLIB_ROOT}/install/lib" CPPFLAGS="-I${PCEPLIB_ROOT}/install/include" +``` + +To start pathd with pcep support the extra parameter `-M pathd_pcep` should be +passed to the pathd daemon. + + +Pathd Configuration +=================== + +Example: + +.. code-block:: frr + + debug pathd pcep basic + segment-routing + traffic-eng + segment-list SL1 + index 10 mpls label 16010 + index 20 mpls label 16030 + ! + policy color 1 endpoint 1.1.1.1 + name default + binding-sid 4000 + candidate-path preference 100 name CP1 explicit segment-list SL1 + candidate-path preference 200 name CP2 dynamic + affinity include-any 0x000000FF + bandwidth 100000 + metric bound msd 16 required + metric te 10 + objective-function mcp required + ! + pcep + pce-config GROUP1 + source-address 1.1.1.1 + tcp-md5-auth secret + timer keep-alive 30 + ! + pce PCE1 + config GROUP1 + address ip 10.10.10.10 + ! + pce PCE2 + config GROUP1 + address ip 9.9.9.9 + ! + pcc + peer PCE1 precedence 10 + peer PCE2 precedence 20 + ! + ! + ! + ! + + +.. _path-commands: + +Configuration Commands +---------------------- + +.. index:: segment-routing +.. clicmd:: segment-routing + + Configure segment routing. + +.. index:: traffic-eng +.. clicmd:: traffic-eng + + Configure segment routing traffic engineering. + +.. index:: segment-list NAME +.. clicmd:: [no] segment-list NAME + + Delete or start a segment list definition. + + +.. index:: index INDEX mpls label LABEL [nai node ADDRESS] +.. clicmd:: [no] index INDEX mpls label LABEL [nai node ADDRESS] + + Delete or specify a segment in a segment list definition. + + +.. index:: policy color COLOR endpoint ENDPOINT +.. clicmd:: [no] policy color COLOR endpoint ENDPOINT + + Delete or start a policy definition. + + +.. index:: name NAME +.. clicmd:: name NAME + + Specify the policy name. + + +.. index:: binding-sid LABEL +.. clicmd:: binding-sid LABEL + + Specify the policy SID. + + +.. index:: candidate-path preference PREFERENCE name NAME explicit segment-list SEGMENT-LIST-NAME +.. clicmd:: [no] candidate-path preference PREFERENCE name NAME explicit segment-list SEGMENT-LIST-NAME + + Delete or define an explicit candidate path. + + +.. index:: candidate-path preference PREFERENCE name NAME dynamic +.. clicmd:: [no] candidate-path preference PREFERENCE name NAME dynamic + + Delete or start a dynamic candidate path definition. + + +.. index:: affinity {exclude-any|include-any|include-all} BITPATTERN +.. clicmd:: [no] affinity {exclude-any|include-any|include-all} BITPATTERN + + Delete or specify an affinity constraint for a dynamic candidate path. + + +.. index:: bandwidth BANDWIDTH [required] +.. clicmd:: [no] bandwidth BANDWIDTH [required] + + Delete or specify a bandwidth constraint for a dynamic candidate path. + + +.. index:: metric [bound] METRIC VALUE [required] +.. clicmd:: [no] metric [bound] METRIC VALUE [required] + + Delete or specify a metric constraint for a dynamic candidate path. + + The possible metrics are: + - igp: IGP metric + - te: TE metric + - hc: Hop Counts + - abc: Aggregate bandwidth consumption + - mll: Load of the most loaded link + - igp: Cumulative IGP cost + - cte: Cumulative TE cost + - igp: P2MP IGP metric + - pte: P2MP TE metric + - phc: P2MP hop count metric + - msd: Segment-ID (SID) Depth + - pd: Path Delay metric + - pdv: Path Delay Variation metric + - pl: Path Loss metric + - ppd: P2MP Path Delay metric + - pdv: P2MP Path Delay variation metric + - ppl: P2MP Path Loss metric + - nap: Number of adaptations on a path + - nlp: Number of layers on a path + - dc: Domain Count metric + - bnc: Border Node Count metric + + +.. index:: objective-function OBJFUN1 [required] +.. clicmd:: [no] objective-function OBJFUN1 [required] + + Delete or specify a PCEP objective function constraint for a dynamic + candidate path. + + The possible functions are: + - mcp: Minimum Cost Path [RFC5541] + - mlp: Minimum Load Path [RFC5541] + - mbp: Maximum residual Bandwidth Path [RFC5541] + - mbc: Minimize aggregate Bandwidth Consumption [RFC5541] + - mll: Minimize the Load of the most loaded Link [RFC5541] + - mcc: Minimize the Cumulative Cost of a set of paths [RFC5541] + - spt: Shortest Path Tree [RFC8306] + - mct: Minimum Cost Tree [RFC8306] + - mplp: Minimum Packet Loss Path [RFC8233] + - mup: Maximum Under-Utilized Path [RFC8233] + - mrup: Maximum Reserved Under-Utilized Path [RFC8233] + - mtd: Minimize the number of Transit Domains [RFC8685] + - mbn: Minimize the number of Border Nodes [RFC8685] + - mctd: Minimize the number of Common Transit Domains [RFC8685] + - msl: Minimize the number of Shared Links [RFC8800] + - mss: Minimize the number of Shared SRLGs [RFC8800] + - msn: Minimize the number of Shared Nodes [RFC8800] + + +.. index:: debug pathd pcep [basic|path|message|pceplib] +.. clicmd:: [no] debug pathd pcep [basic|path|message|pceplib] + + Enable or disable debugging for the pcep module: + + - basic: Enable basic PCEP logging + - path: Log the path structures + - message: Log the PCEP messages + - pceplib: Enable pceplib logging + + +.. index:: pcep +.. clicmd:: pcep + + Configure PCEP support. + + +.. index:: cep-config NAME +.. clicmd:: [no] pce-config NAME + + Define a shared PCE configuration that can be used in multiple PCE + declarations. + + +.. index:: pce NAME +.. clicmd:: [no] pce NAME + + Define or delete a PCE definition. + + +.. index:: config WORD +.. clicmd:: config WORD + + Select a shared configuration. If not defined, the default + configuration will be used. + + +.. index:: address <ip A.B.C.D | ipv6 X:X::X:X> [port (1024-65535)] +.. clicmd:: address <ip A.B.C.D | ipv6 X:X::X:X> [port (1024-65535)] + + Define the address and port of the PCE. + + If not specified, the port is the standard PCEP port 4189. + + This should be specified in the PCC peer definition. + + +.. index:: source-address [ip A.B.C.D | ipv6 X:X::X:X] [port PORT] +.. clicmd:: source-address [ip A.B.C.D | ipv6 X:X::X:X] [port PORT] + + Define the address and/or port of the PCC as seen by the PCE. + This can be used in a configuration group or a PCC peer declaration. + + If not specified, the source address will be the router identifier selected + by zebra, and the port will be the standard PCEP port 4189. + + This can be specified in either the PCC peer definition or in a + configuration group. + + +.. index:: tcp-md5-auth WORD +.. clicmd:: tcp-md5-auth WORD + + Enable TCP MD5 security with the given secret. + + This can be specified in either the PCC peer definition or in a + configuration group. + + +.. index:: sr-draft07 +.. clicmd:: sr-draft07 + + Specify if a PCE only support segment routing draft 7, this flag will limit + the PCC behavior to this draft. + + This can be specified in either the PCC peer definition or in a + configuration group. + + +.. index:: pce-initiated +.. clicmd:: pce-initiated + + Specify if PCE-initiated LSP should be allowed for this PCE. + + This can be specified in either the PCC peer definition or in a + configuration group. + + +.. index:: timer [keep-alive (1-63)] [min-peer-keep-alive (1-255)] [max-peer-keep-alive (1-255)] [dead-timer (4-255)] [min-peer-dead-timer (4-255)] [max-peer-dead-timer (4-255)] [pcep-request (1-120)] [session-timeout-interval (1-120)] [delegation-timeout (1-60)] +.. clicmd:: timer [keep-alive (1-63)] [min-peer-keep-alive (1-255)] [max-peer-keep-alive (1-255)] [dead-timer (4-255)] [min-peer-dead-timer (4-255)] [max-peer-dead-timer (4-255)] [pcep-request (1-120)] [session-timeout-interval (1-120)] [delegation-timeout (1-60)] + + Specify the PCEP timers. + + This can be specified in either the PCC peer definition or in a + configuration group. + + +.. index:: pcc +.. clicmd:: [no] pcc + + Disable or start the definition of a PCC. + + +.. index:: msd (1-32) +.. clicmd:: msd (1-32) + + Specify the maximum SID depth in a PCC definition. + + +.. index:: peer WORD [precedence (1-255)] +.. clicmd:: [no] peer WORD [precedence (1-255)] + + Specify a peer and its precedence in a PCC definition. + + +Introspection Commands +---------------------- + +.. index:: show sr-te policy [detail] +.. clicmd:: show sr-te policy [detail] + + Display the segment routing policies. + +.. code-block:: frr + + router# show sr-te policy + + Endpoint Color Name BSID Status + ------------------------------------------ + 1.1.1.1 1 default 4000 Active + + +.. code-block:: frr + + router# show sr-te policy detail + + Endpoint: 1.1.1.1 Color: 1 Name: LOW_DELAY BSID: 4000 Status: Active + Preference: 100 Name: cand1 Type: explicit Segment-List: sl1 Protocol-Origin: Local + * Preference: 200 Name: cand1 Type: dynamic Segment-List: 32453452 Protocol-Origin: PCEP + +The asterisk (*) marks the best, e.g. active, candidate path. Note that for segment-lists which are +retrieved via PCEP a random number based name is generated. + + +.. index:: show debugging pathd +.. clicmd:: show debugging pathd + + Display the current status of the pathd debugging. + + +.. index:: show debugging pathd-pcep +.. clicmd:: show debugging pathd-pcep + + Display the current status of the pcep module debugging. + + +.. index:: show sr-te pcep counters +.. clicmd:: show sr-te pcep counters + + Display the counters from pceplib. + + +.. index:: show sr-te pcep pce-config [NAME] +.. clicmd:: show sr-te pcep pce-config [NAME] + + Display a shared configuration. if no name is specified, the default + configuration will be displayed. + + +.. index:: show sr-te pcep pcc +.. clicmd:: show sr-te pcep pcc + + Display PCC information. + + +.. index:: show sr-te pcep session [NAME] +.. clicmd:: show sr-te pcep session [NAME] + + Display the information of a PCEP session, if not name is specified all the + sessions will be displayed. + + +Utility Commands +---------------- + +.. index:: clear sr-te pcep session [NAME] +.. clicmd:: clear sr-te pcep session [NAME] + + Reset the pcep session by disconnecting from the PCE and performing the + normal reconnection process. No configuration is changed. + + +Usage with BGP route-maps +========================= + +It is possible to steer traffic 'into' a segment routing policy for routes +learned through BGP using route-maps: + +.. code-block:: frr + + route-map SET_SR_POLICY permit 10 + set sr-te color 1 + ! + router bgp 1 + bgp router-id 2.2.2.2 + neighbor 1.1.1.1 remote-as 1 + neighbor 1.1.1.1 update-source lo + ! + address-family ipv4 unicast + neighbor 1.1.1.1 next-hop-self + neighbor 1.1.1.1 route-map SET_SR_POLICY in + redistribute static + exit-address-family + ! + ! + +In this case, the SR Policy with color `1` and endpoint `1.1.1.1` is selected. diff --git a/doc/user/pbr.rst b/doc/user/pbr.rst index c869c6bc45..5cec7cbe62 100644 --- a/doc/user/pbr.rst +++ b/doc/user/pbr.rst @@ -258,6 +258,21 @@ causes the policy to be installed into the kernel. | valid | Is the map well-formed? | Boolean | +--------+----------------------------+---------+ +.. _pbr-debugs: + +PBR Debugs +=========== + +.. index:: debug pbr +.. clicmd:: debug pbr events|map|nht|zebra + + Debug pbr in pbrd daemon. You specify what types of debugs to turn on. + +.. index:: debug zebra pbr +.. clicmd:: debug zebra pbr + + Debug pbr in zebra daemon. + .. _pbr-details: PBR Details diff --git a/doc/user/pim.rst b/doc/user/pim.rst index dd6a647b4f..201fe2f9ed 100644 --- a/doc/user/pim.rst +++ b/doc/user/pim.rst @@ -727,6 +727,13 @@ Clear commands reset various variables. Rescan PIM OIL (output interface list). +.. index:: clear ip pim [vrf NAME] bsr-data +.. clicmd:: clear ip pim [vrf NAME] bsr-data + + This command will clear the BSM scope data struct. This command also + removes the next hop tracking for the bsr and resets the upstreams + for the dynamically learnt RPs. + PIM EVPN configuration ====================== To use PIM in the underlay for overlay BUM forwarding associate a multicast diff --git a/doc/user/rpki.rst b/doc/user/rpki.rst index 2c0e5876fa..451df1aa4e 100644 --- a/doc/user/rpki.rst +++ b/doc/user/rpki.rst @@ -271,5 +271,5 @@ RPKI Configuration Example route-map rpki permit 40 ! -.. [Securing-BGP] Geoff Huston, Randy Bush: Securing BGP, In: The Internet Protocol Journal, Volume 14, No. 2, 2011. <http://www.cisco.com/web/about/ac123/ac147/archived_issues/ipj_14-2/142_bgp.html> -.. [Resource-Certification] Geoff Huston: Resource Certification, In: The Internet Protocol Journal, Volume 12, No.1, 2009. <http://www.cisco.com/web/about/ac123/ac147/archived_issues/ipj_12-1/121_resource.html> +.. [Securing-BGP] Geoff Huston, Randy Bush: Securing BGP, In: The Internet Protocol Journal, Volume 14, No. 2, 2011. <https://www.cisco.com/c/dam/en_us/about/ac123/ac147/archived_issues/ipj_14-2/ipj_14-2.pdf> +.. [Resource-Certification] Geoff Huston: Resource Certification, In: The Internet Protocol Journal, Volume 12, No.1, 2009. <https://www.cisco.com/c/dam/en_us/about/ac123/ac147/archived_issues/ipj_12-1/ipj_12-1.pdf> diff --git a/doc/user/scripting.rst b/doc/user/scripting.rst new file mode 100644 index 0000000000..b0295e5706 --- /dev/null +++ b/doc/user/scripting.rst @@ -0,0 +1,28 @@ +.. _scripting: + +********* +Scripting +********* + +The behavior of FRR may be extended or customized using its built-in scripting +capabilities. + +Some configuration commands accept the name of a Lua script to call to perform +some task or make some decision. These scripts have their environments +populated with some set of inputs, and are expected to populate some set of +output variables, which are read by FRR after the script completes. The names +and expected contents of these scripts are documented alongside the commands +that support them. + +These scripts live in :file:`/etc/frr/scripts/` by default. This is +configurable at compile time via ``--with-scriptdir``. It may be +overriden at runtime with the ``--scriptdir`` daemon option. + +In order to use scripting, FRR must be built with ``--enable-scripting``. + +.. note:: + + Scripts are typically loaded just-in-time. This means you can change the + contents of a script that is in use without restarting FRR. Not all + scripting locations may behave this way; refer to the documentation for the + particular location. diff --git a/doc/user/setup.rst b/doc/user/setup.rst index b2b71cf012..64a33765c2 100644 --- a/doc/user/setup.rst +++ b/doc/user/setup.rst @@ -240,3 +240,53 @@ because FRR's monitoring program cannot currently distinguish between a crashed The closest that can be achieved is to remove all configuration for the daemon, and set its line in ``/etc/frr/daemons`` to ``=no``. Once this is done, the daemon will be stopped the next time FRR is restarted. + + +Network Namespaces +^^^^^^^^^^^^^^^^^^ + +It is possible to run FRR in different network namespaces so it can be +further compartmentalized (e.g. confining to a smaller subset network). +The network namespace configuration can be used in the default FRR +configuration pathspace or it can be used in a different pathspace +(`-N/--pathspace`). + +To use FRR network namespace in the default pathspace you should add +or uncomment the ``watchfrr_options`` line in ``/etc/frr/daemons``: + +.. code-block:: diff + + - #watchfrr_options="--netns" + + watchfrr_options="--netns=<network-namespace-name>" + +If you want to use a different pathspace with the network namespace +(the recommended way) you should add/uncomment the ``watchfrr_options`` +line in ``/etc/frr/<namespace>/daemons``: + +.. code-block:: diff + + - #watchfrr_options="--netns" + + #watchfrr_options="--netns=<network-namespace-name>" + + + + # `--netns` argument is optional and if not provided it will + + # default to the pathspace name. + + watchfrr_options="--netns" + +To start FRR in the new pathspace+network namespace the initialization script +should be called with an extra parameter: + + +.. code:: + + /etc/init.d/frr start <pathspace-name> + + +.. note:: + + Some Linux distributions might not use the default init script + shipped with FRR, in that case you might want to try running the + bundled script in ``/usr/lib/frr/frrinit.sh``. + + On systemd you might create different units or parameterize the + existing one. See the man page: + https://www.freedesktop.org/software/systemd/man/systemd.unit.html diff --git a/doc/user/subdir.am b/doc/user/subdir.am index dd7a193e34..3585245e85 100644 --- a/doc/user/subdir.am +++ b/doc/user/subdir.am @@ -27,6 +27,7 @@ user_RSTFILES = \ doc/user/ospf_fundamentals.rst \ doc/user/overview.rst \ doc/user/packet-dumps.rst \ + doc/user/pathd.rst \ doc/user/pim.rst \ doc/user/ripd.rst \ doc/user/pbr.rst \ @@ -34,6 +35,7 @@ user_RSTFILES = \ doc/user/routemap.rst \ doc/user/routeserver.rst \ doc/user/rpki.rst \ + doc/user/scripting.rst \ doc/user/setup.rst \ doc/user/sharp.rst \ doc/user/snmp.rst \ diff --git a/doc/user/zebra.rst b/doc/user/zebra.rst index 91cd205bed..a9979558c3 100644 --- a/doc/user/zebra.rst +++ b/doc/user/zebra.rst @@ -407,6 +407,14 @@ If no option is chosen, then the *Linux VRF* implementation as references in https://www.kernel.org/doc/Documentation/networking/vrf.txt will be mapped over the *Zebra* VRF. The routing table associated to that VRF is a Linux table identifier located in the same *Linux network namespace* where *Zebra* started. +Please note when using the *Linux VRF* routing table it is expected that a +default Kernel route will be installed that has a metric as outlined in the +www.kernel.org doc above. The Linux Kernel does table lookup via a combination +of rule application of the rule table and then route lookup of the specified +table. If no route match is found then the next applicable rule is applied +to find the next route table to use to look for a route match. As such if +your VRF table does not have a default blackhole route with a high metric +VRF route lookup will leave the table specified by the VRF, which is undesirable. If the :option:`-n` option is chosen, then the *Linux network namespace* will be mapped over the *Zebra* VRF. That implies that *Zebra* is able to configure @@ -759,6 +767,12 @@ IPv6 example for OSPFv3. not created at startup. On Debian, FRR might start before ifupdown completes. Consider a reboot test. +.. index:: zebra route-map delay-timer (0-600) +.. clicmd:: [no] zebra route-map delay-timer (0-600) + + Set the delay before any route-maps are processed in zebra. The + default time for this is 5 seconds. + .. _zebra-fib-push-interface: zebra FIB push interface |
