mirror of
https://git.proxmox.com/git/mirror_frr
synced 2025-08-05 20:07:46 +00:00
Merge pull request #7351 from opensourcerouting/feature/pathd
Add a new SR-TE policy management daemon and an optional PCEP module
This commit is contained in:
commit
065f7c7cc0
@ -158,6 +158,7 @@ include bfdd/subdir.am
|
||||
include yang/subdir.am
|
||||
include yang/libyang_plugins/subdir.am
|
||||
include vrrpd/subdir.am
|
||||
include pathd/subdir.am
|
||||
|
||||
include vtysh/subdir.am
|
||||
include tests/subdir.am
|
||||
|
25
configure.ac
25
configure.ac
@ -560,6 +560,8 @@ AC_ARG_ENABLE([fabricd],
|
||||
AS_HELP_STRING([--disable-fabricd], [do not build fabricd]))
|
||||
AC_ARG_ENABLE([vrrpd],
|
||||
AS_HELP_STRING([--disable-vrrpd], [do not build vrrpd]))
|
||||
AC_ARG_ENABLE([pathd],
|
||||
AS_HELP_STRING([--disable-pathd], [do not build pathd]))
|
||||
AC_ARG_ENABLE([bgp-announce],
|
||||
AS_HELP_STRING([--disable-bgp-announce], [turn off BGP route announcement]))
|
||||
AC_ARG_ENABLE([bgp-vnc],
|
||||
@ -625,6 +627,8 @@ AC_ARG_ENABLE([pcreposix],
|
||||
AS_HELP_STRING([--enable-pcreposix], [enable using PCRE Posix libs for regex functions]))
|
||||
AC_ARG_ENABLE([fpm],
|
||||
AS_HELP_STRING([--enable-fpm], [enable Forwarding Plane Manager support]))
|
||||
AC_ARG_ENABLE([pcep],
|
||||
AS_HELP_STRING([--enable-pcep], [enable PCEP support for pathd]))
|
||||
AC_ARG_ENABLE([systemd],
|
||||
AS_HELP_STRING([--enable-systemd], [enable Systemd support]))
|
||||
AC_ARG_ENABLE([werror],
|
||||
@ -1675,6 +1679,14 @@ else
|
||||
esac
|
||||
fi
|
||||
|
||||
AS_IF([test "$enable_pathd" != "no"], [
|
||||
AC_DEFINE([HAVE_PATHD], [1], [pathd])
|
||||
])
|
||||
|
||||
AS_IF([test "$enable_pcep" != "no"], [
|
||||
AC_DEFINE([HAVE_PATHD_PCEP], [1], [pathd-pcep])
|
||||
])
|
||||
|
||||
if test "$ac_cv_lib_json_c_json_object_get" = "no" -a "$BFDD" = "bfdd"; then
|
||||
AC_MSG_ERROR(["you must use json-c library to use bfdd"])
|
||||
fi
|
||||
@ -2467,6 +2479,18 @@ AM_CONDITIONAL([IRDP], [$IRDP])
|
||||
AM_CONDITIONAL([FPM], [test "$enable_fpm" = "yes"])
|
||||
AM_CONDITIONAL([HAVE_PROTOBUF], [test "$enable_protobuf" = "yes"])
|
||||
AM_CONDITIONAL([HAVE_PROTOBUF3], [$PROTO3])
|
||||
|
||||
dnl PCEP plugin
|
||||
AM_CONDITIONAL([HAVE_PATHD_PCEP], [test "$enable_pcep" = "yes"])
|
||||
AS_IF([test "$enable_pcep" = "yes"], [
|
||||
AC_CHECK_LIB([pcep_pcc], [initialize_pcc], [
|
||||
PATHD_PCEP_LIBS="-lpcep_pcc"
|
||||
],[
|
||||
AC_MSG_ERROR([PCEP library libpcep_pcc not found])
|
||||
])
|
||||
AC_SUBST([PATHD_PCEP_LIBS])
|
||||
])
|
||||
|
||||
dnl daemons
|
||||
AM_CONDITIONAL([VTYSH], [test "$VTYSH" = "vtysh"])
|
||||
AM_CONDITIONAL([ZEBRA], [test "$enable_zebra" != "no"])
|
||||
@ -2489,6 +2513,7 @@ AM_CONDITIONAL([SHARPD], [test "$enable_sharpd" = "yes"])
|
||||
AM_CONDITIONAL([STATICD], [test "$enable_staticd" != "no"])
|
||||
AM_CONDITIONAL([FABRICD], [test "$enable_fabricd" != "no"])
|
||||
AM_CONDITIONAL([VRRPD], [test "$enable_vrrpd" != "no"])
|
||||
AM_CONDITIONAL([PATHD], [test "$enable_pathd" != "no"])
|
||||
|
||||
AC_CONFIG_FILES([Makefile],[
|
||||
test "$enable_dev_build" = "yes" && makefile_devbuild="--dev-build"
|
||||
|
@ -18,3 +18,4 @@ FRRouting Developer's Guide
|
||||
ospf
|
||||
zebra
|
||||
vtysh
|
||||
pathd
|
||||
|
115
doc/developer/path-internals-daemon.rst
Normal file
115
doc/developer/path-internals-daemon.rst
Normal file
@ -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.
|
193
doc/developer/path-internals-pcep.rst
Normal file
193
doc/developer/path-internals-pcep.rst
Normal file
@ -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.
|
11
doc/developer/path-internals.rst
Normal file
11
doc/developer/path-internals.rst
Normal file
@ -0,0 +1,11 @@
|
||||
.. _path_internals:
|
||||
|
||||
*********
|
||||
Internals
|
||||
*********
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 2
|
||||
|
||||
path-internals-daemon
|
||||
path-internals-pcep
|
11
doc/developer/path.rst
Normal file
11
doc/developer/path.rst
Normal file
@ -0,0 +1,11 @@
|
||||
.. _path:
|
||||
|
||||
*****
|
||||
PATHD
|
||||
*****
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 2
|
||||
|
||||
path-internals
|
||||
|
@ -46,6 +46,10 @@ 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/static-linking.rst \
|
||||
doc/developer/testing.rst \
|
||||
|
481
doc/figures/pcep_module_threading_overview.svg
Normal file
481
doc/figures/pcep_module_threading_overview.svg
Normal file
File diff suppressed because one or more lines are too long
After Width: | Height: | Size: 64 KiB |
@ -50,6 +50,7 @@ Protocols
|
||||
nhrpd
|
||||
ospfd
|
||||
ospf6d
|
||||
pathd
|
||||
pim
|
||||
pbr
|
||||
ripd
|
||||
|
443
doc/user/pathd.rst
Normal file
443
doc/user/pathd.rst
Normal file
@ -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:: [no] segment-list NAME
|
||||
.. clicmd:: [no] segment-list NAME
|
||||
|
||||
Delete or start a segment list definition.
|
||||
|
||||
|
||||
.. index:: [no] 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:: [no] 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:: [no] 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:: [no] 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:: [no] 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:: [no] bandwidth BANDWIDTH [required]
|
||||
.. clicmd:: [no] bandwidth BANDWIDTH [required]
|
||||
|
||||
Delete or specify a bandwidth constraint for a dynamic candidate path.
|
||||
|
||||
|
||||
.. index:: [no] 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:: [no] 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:: [no] 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:: [no] cep-config NAME
|
||||
.. clicmd:: [no] pce-config NAME
|
||||
|
||||
Define a shared PCE configuration that can be used in multiple PCE
|
||||
declarations.
|
||||
|
||||
|
||||
.. index:: [no] 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:: [no] 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:: [no] 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.
|
@ -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 \
|
||||
|
@ -863,6 +863,30 @@ enum node_type node_parent(enum node_type node)
|
||||
case BFD_PROFILE_NODE:
|
||||
ret = BFD_NODE;
|
||||
break;
|
||||
case SR_TRAFFIC_ENG_NODE:
|
||||
ret = SEGMENT_ROUTING_NODE;
|
||||
break;
|
||||
case SR_SEGMENT_LIST_NODE:
|
||||
ret = SR_TRAFFIC_ENG_NODE;
|
||||
break;
|
||||
case SR_POLICY_NODE:
|
||||
ret = SR_TRAFFIC_ENG_NODE;
|
||||
break;
|
||||
case SR_CANDIDATE_DYN_NODE:
|
||||
ret = SR_POLICY_NODE;
|
||||
break;
|
||||
case PCEP_NODE:
|
||||
ret = SR_TRAFFIC_ENG_NODE;
|
||||
break;
|
||||
case PCEP_PCE_CONFIG_NODE:
|
||||
ret = PCEP_NODE;
|
||||
break;
|
||||
case PCEP_PCE_NODE:
|
||||
ret = PCEP_NODE;
|
||||
break;
|
||||
case PCEP_PCC_NODE:
|
||||
ret = PCEP_NODE;
|
||||
break;
|
||||
default:
|
||||
ret = CONFIG_NODE;
|
||||
break;
|
||||
|
@ -145,6 +145,15 @@ enum node_type {
|
||||
PROTOCOL_NODE, /* protocol filtering node */
|
||||
MPLS_NODE, /* MPLS config node */
|
||||
PW_NODE, /* Pseudowire config node */
|
||||
SEGMENT_ROUTING_NODE, /* Segment routing root node */
|
||||
SR_TRAFFIC_ENG_NODE, /* SR Traffic Engineering node */
|
||||
SR_SEGMENT_LIST_NODE, /* SR segment list config node */
|
||||
SR_POLICY_NODE, /* SR policy config node */
|
||||
SR_CANDIDATE_DYN_NODE, /* SR dynamic candidate path config node */
|
||||
PCEP_NODE, /* PCEP node */
|
||||
PCEP_PCE_CONFIG_NODE, /* PCE shared configuration node */
|
||||
PCEP_PCE_NODE, /* PCE configuration node */
|
||||
PCEP_PCC_NODE, /* PCC configuration node */
|
||||
VTY_NODE, /* Vty node. */
|
||||
FPM_NODE, /* Dataplane FPM node. */
|
||||
LINK_PARAMS_NODE, /* Link-parameters node */
|
||||
|
@ -132,6 +132,8 @@ struct ferr {
|
||||
#define VTYSH_FRR_END 0x0FFFFFFF
|
||||
#define WATCHFRR_FERR_START 0x10000001
|
||||
#define WATCHFRR_FERR_END 0x10FFFFFF
|
||||
#define PATH_FERR_START 0x11000001
|
||||
#define PATH_FERR_END 0x11FFFFFF
|
||||
#define ZEBRA_FERR_START 0xF1000001
|
||||
#define ZEBRA_FERR_END 0xF1FFFFFF
|
||||
#define END_FERR 0xFFFFFFFF
|
||||
|
@ -600,6 +600,7 @@ enum nb_client {
|
||||
NB_CLIENT_CONFD,
|
||||
NB_CLIENT_SYSREPO,
|
||||
NB_CLIENT_GRPC,
|
||||
NB_CLIENT_PCEP,
|
||||
};
|
||||
|
||||
/* Northbound context. */
|
||||
@ -621,6 +622,8 @@ struct nb_context {
|
||||
} sysrepo;
|
||||
struct {
|
||||
} grpc;
|
||||
struct {
|
||||
} pcep;
|
||||
} client_data;
|
||||
#endif
|
||||
};
|
||||
|
@ -92,6 +92,7 @@ static const char *const frr_native_modules[] = {
|
||||
"frr-isisd",
|
||||
"frr-vrrpd",
|
||||
"frr-zebra",
|
||||
"frr-pathd",
|
||||
};
|
||||
/* clang-format on */
|
||||
|
||||
|
2
pathd/.gitignore
vendored
Normal file
2
pathd/.gitignore
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
libpath.a
|
||||
pathd
|
10
pathd/Makefile
Normal file
10
pathd/Makefile
Normal file
@ -0,0 +1,10 @@
|
||||
all: ALWAYS
|
||||
@$(MAKE) -s -C .. pathd/pathd
|
||||
%: ALWAYS
|
||||
@$(MAKE) -s -C .. pathd/$@
|
||||
|
||||
Makefile:
|
||||
#nothing
|
||||
ALWAYS:
|
||||
.PHONY: ALWAYS makefiles
|
||||
.SUFFIXES:
|
1108
pathd/path_cli.c
Normal file
1108
pathd/path_cli.c
Normal file
File diff suppressed because it is too large
Load Diff
121
pathd/path_debug.c
Normal file
121
pathd/path_debug.c
Normal file
@ -0,0 +1,121 @@
|
||||
/*
|
||||
* Copyright (C) 2020 NetDEF, Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the Free
|
||||
* Software Foundation; either version 2 of the License, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; see the file COPYING; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include <stdbool.h>
|
||||
#include <time.h>
|
||||
#include <libyang/libyang.h>
|
||||
|
||||
#include "printfrr.h"
|
||||
#include "ipaddr.h"
|
||||
|
||||
#include "pathd/path_debug.h"
|
||||
|
||||
THREAD_DATA char _debug_buff[DEBUG_BUFF_SIZE];
|
||||
|
||||
/**
|
||||
* Gives the string representation of an srte_protocol_origin enum value.
|
||||
*
|
||||
* @param origin The enum value to convert to string
|
||||
* @return a constant string representation of the enum value
|
||||
*/
|
||||
const char *srte_protocol_origin_name(enum srte_protocol_origin origin)
|
||||
{
|
||||
switch (origin) {
|
||||
case SRTE_ORIGIN_UNDEFINED:
|
||||
return "UNDEFINED";
|
||||
case SRTE_ORIGIN_PCEP:
|
||||
return "PCEP";
|
||||
case SRTE_ORIGIN_BGP:
|
||||
return "BGP";
|
||||
case SRTE_ORIGIN_LOCAL:
|
||||
return "LOCAL";
|
||||
default:
|
||||
return "UNKNOWN";
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gives the string representation of an srte_candidate_type enum value.
|
||||
*
|
||||
* @param origin The enum value to convert to string
|
||||
* @return a constant string representation of the enum value
|
||||
*/
|
||||
const char *srte_candidate_type_name(enum srte_candidate_type type)
|
||||
{
|
||||
switch (type) {
|
||||
case SRTE_CANDIDATE_TYPE_EXPLICIT:
|
||||
return "EXPLICIT";
|
||||
case SRTE_CANDIDATE_TYPE_DYNAMIC:
|
||||
return "DYNAMIC";
|
||||
case SRTE_CANDIDATE_TYPE_UNDEFINED:
|
||||
return "UNDEFINED";
|
||||
default:
|
||||
return "UNKNOWN";
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gives the string representation of an objfun_type enum value.
|
||||
*
|
||||
* @param origin The enum value to convert to string
|
||||
* @return a constant string representation of the enum value
|
||||
*/
|
||||
const char *objfun_type_name(enum objfun_type type)
|
||||
{
|
||||
switch (type) {
|
||||
case OBJFUN_UNDEFINED:
|
||||
return "UNDEFINED";
|
||||
case OBJFUN_MCP:
|
||||
return "MCP";
|
||||
case OBJFUN_MLP:
|
||||
return "MLP";
|
||||
case OBJFUN_MBP:
|
||||
return "MBP";
|
||||
case OBJFUN_MBC:
|
||||
return "MBC";
|
||||
case OBJFUN_MLL:
|
||||
return "MLL";
|
||||
case OBJFUN_MCC:
|
||||
return "MCC";
|
||||
case OBJFUN_SPT:
|
||||
return "SPT";
|
||||
case OBJFUN_MCT:
|
||||
return "MCT";
|
||||
case OBJFUN_MPLP:
|
||||
return "MPLP";
|
||||
case OBJFUN_MUP:
|
||||
return "MUP";
|
||||
case OBJFUN_MRUP:
|
||||
return "MRUP";
|
||||
case OBJFUN_MTD:
|
||||
return "MTD";
|
||||
case OBJFUN_MBN:
|
||||
return "MBN";
|
||||
case OBJFUN_MCTD:
|
||||
return "MCTD";
|
||||
case OBJFUN_MSL:
|
||||
return "MSL";
|
||||
case OBJFUN_MSS:
|
||||
return "MSS";
|
||||
case OBJFUN_MSN:
|
||||
return "MSN";
|
||||
default:
|
||||
return "UNKNOWN";
|
||||
}
|
||||
}
|
44
pathd/path_debug.h
Normal file
44
pathd/path_debug.h
Normal file
@ -0,0 +1,44 @@
|
||||
/*
|
||||
* Copyright (C) 2020 NetDEF, Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the Free
|
||||
* Software Foundation; either version 2 of the License, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; see the file COPYING; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#ifndef _PATH_DEBUG_H_
|
||||
#define _PATH_DEBUG_H_
|
||||
|
||||
#include "pathd/pathd.h"
|
||||
|
||||
#ifdef __GNUC__
|
||||
#define THREAD_DATA __thread
|
||||
#else
|
||||
#define THREAD_DATA
|
||||
#endif
|
||||
|
||||
#define DEBUG_IDENT_SIZE 4
|
||||
#define DEBUG_BUFF_SIZE 4096
|
||||
#define TUP(A, B) ((((uint32_t)(A)) << 16) | ((uint32_t)(B)))
|
||||
#define PATHD_FORMAT_INIT() _debug_buff[0] = 0
|
||||
#define PATHD_FORMAT(fmt, ...) \
|
||||
csnprintfrr(_debug_buff, DEBUG_BUFF_SIZE, fmt, ##__VA_ARGS__)
|
||||
#define PATHD_FORMAT_FINI() _debug_buff
|
||||
|
||||
extern THREAD_DATA char _debug_buff[DEBUG_BUFF_SIZE];
|
||||
|
||||
const char *srte_protocol_origin_name(enum srte_protocol_origin origin);
|
||||
const char *srte_candidate_type_name(enum srte_candidate_type type);
|
||||
const char *objfun_type_name(enum objfun_type type);
|
||||
|
||||
#endif // _PATH_DEBUG_H_
|
134
pathd/path_errors.c
Normal file
134
pathd/path_errors.c
Normal file
@ -0,0 +1,134 @@
|
||||
/*
|
||||
* pathd-specific error messages.
|
||||
* Copyright (C) 2020 NetDEF, Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the Free
|
||||
* Software Foundation; either version 2 of the License, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; see the file COPYING; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include <zebra.h>
|
||||
|
||||
#include "lib/ferr.h"
|
||||
#include "path_errors.h"
|
||||
|
||||
/* clang-format off */
|
||||
static struct log_ref ferr_path_err[] = {
|
||||
{
|
||||
.code = EC_PATH_SYSTEM_CALL,
|
||||
.title = "Thread setup error",
|
||||
.description = "A system call for creating, or setting up PCEP module's pthread failed",
|
||||
.suggestion = "Open an Issue with all relevant log files and restart FRR"
|
||||
},
|
||||
{
|
||||
.code = EC_PATH_PCEP_PCC_INIT,
|
||||
.title = "PCC initialization error",
|
||||
.description = "pceplib PCC initialization call failed",
|
||||
.suggestion = "Open an Issue with all relevant log files and restart FRR"
|
||||
},
|
||||
{
|
||||
.code = EC_PATH_PCEP_PCC_FINI,
|
||||
.title = "PCC finalization error",
|
||||
.description = "pceplib PCC finalization call failed",
|
||||
.suggestion = "Open an Issue with all relevant log files and restart FRR"
|
||||
},
|
||||
{
|
||||
.code = EC_PATH_PCEP_PCC_CONF_UPDATE,
|
||||
.title = "PCC configuration update error",
|
||||
.description = "The update of the PCC configuration failed",
|
||||
.suggestion = "Open an Issue with all relevant log files and restart FRR"
|
||||
},
|
||||
{
|
||||
.code = END_FERR,
|
||||
}
|
||||
};
|
||||
|
||||
static struct log_ref ferr_path_warn[] = {
|
||||
{
|
||||
.code = EC_PATH_PCEP_LIB_CONNECT,
|
||||
.title = "PCC connection error",
|
||||
.description = "The PCEP module failed to connected to configured PCE",
|
||||
.suggestion = "Check the connectivity between the PCC and the PCE"
|
||||
},
|
||||
{
|
||||
.code = EC_PATH_PCEP_MISSING_SOURCE_ADDRESS,
|
||||
.title = "PCC connection error",
|
||||
.description = "The PCEP module did not try to connect because it is missing a source address",
|
||||
.suggestion = "Wait for the router ID to be defined or set the PCC source address in the configuration"
|
||||
},
|
||||
{
|
||||
.code = EC_PATH_PCEP_RECOVERABLE_INTERNAL_ERROR,
|
||||
.title = "Recoverable internal error",
|
||||
.description = "Some recoverable internal error",
|
||||
.suggestion = "Open an Issue with all relevant log files"
|
||||
},
|
||||
{
|
||||
.code = EC_PATH_PCEP_UNSUPPORTED_PCEP_FEATURE,
|
||||
.title = "Unsupported PCEP feature",
|
||||
.description = "Receved an unsupported PCEP message",
|
||||
.suggestion = "The PCC and PCE are probably not compatible. Open an Issue with all relevant log files"
|
||||
},
|
||||
{
|
||||
.code = EC_PATH_PCEP_UNEXPECTED_PCEP_MESSAGE,
|
||||
.title = "Unexpected PCEP message",
|
||||
.description = "The PCEP module received an unexpected PCEP message",
|
||||
.suggestion = "Open an Issue with all relevant log files"
|
||||
},
|
||||
{
|
||||
.code = EC_PATH_PCEP_UNEXPECTED_PCEPLIB_EVENT,
|
||||
.title = "Unexpected pceplib event",
|
||||
.description = "The PCEP module received an unexpected event from pceplib",
|
||||
.suggestion = "Open an Issue with all relevant log files"
|
||||
},
|
||||
{
|
||||
.code = EC_PATH_PCEP_UNEXPECTED_PCEP_OBJECT,
|
||||
.title = "Unexpected PCEP object",
|
||||
.description = "The PCEP module received an unexpected PCEP object from a PCE",
|
||||
.suggestion = "Open an Issue with all relevant log files"
|
||||
},
|
||||
{
|
||||
.code = EC_PATH_PCEP_UNEXPECTED_PCEP_TLV,
|
||||
.title = "Unexpected PCEP TLV",
|
||||
.description = "The PCEP module received an unexpected PCEP TLV from a PCE",
|
||||
.suggestion = "Open an Issue with all relevant log files"
|
||||
},
|
||||
{
|
||||
.code = EC_PATH_PCEP_UNEXPECTED_PCEP_ERO_SUBOBJ,
|
||||
.title = "Unexpected PCEP ERO sub-object",
|
||||
.description = "The PCEP module received an unexpected PCEP ERO sub-object from a PCE",
|
||||
.suggestion = "Open an Issue with all relevant log files"
|
||||
},
|
||||
{
|
||||
.code = EC_PATH_PCEP_UNEXPECTED_SR_NAI,
|
||||
.title = "Unexpected PCEP SR segment NAI",
|
||||
.description = "The PCEP module received an SR segment with an unsupported NAI specification from the PCE",
|
||||
.suggestion = "Open an Issue with all relevant log files"
|
||||
},
|
||||
{
|
||||
.code = EC_PATH_PCEP_COMPUTATION_REQUEST_TIMEOUT,
|
||||
.title = "Computation request timeout",
|
||||
.description = "The PCE did not respond in time to the PCC computation request",
|
||||
.suggestion = "The PCE is overloaded or incompatible with the PCC, try with a different PCE"
|
||||
},
|
||||
{
|
||||
.code = END_FERR,
|
||||
}
|
||||
|
||||
};
|
||||
/* clang-format on */
|
||||
|
||||
void path_error_init(void)
|
||||
{
|
||||
log_ref_add(ferr_path_err);
|
||||
log_ref_add(ferr_path_warn);
|
||||
}
|
45
pathd/path_errors.h
Normal file
45
pathd/path_errors.h
Normal file
@ -0,0 +1,45 @@
|
||||
/*
|
||||
* Copyright (C) 2020 NetDEF, Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the Free
|
||||
* Software Foundation; either version 2 of the License, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; see the file COPYING; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#ifndef __PATH_ERRORS_H__
|
||||
#define __PATH_ERRORS_H__
|
||||
|
||||
#include "lib/ferr.h"
|
||||
|
||||
enum path_log_refs {
|
||||
EC_PATH_PCEP_INIT = PATH_FERR_START,
|
||||
EC_PATH_SYSTEM_CALL,
|
||||
EC_PATH_PCEP_PCC_INIT,
|
||||
EC_PATH_PCEP_PCC_FINI,
|
||||
EC_PATH_PCEP_PCC_CONF_UPDATE,
|
||||
EC_PATH_PCEP_LIB_CONNECT,
|
||||
EC_PATH_PCEP_MISSING_SOURCE_ADDRESS,
|
||||
EC_PATH_PCEP_RECOVERABLE_INTERNAL_ERROR,
|
||||
EC_PATH_PCEP_UNSUPPORTED_PCEP_FEATURE,
|
||||
EC_PATH_PCEP_UNEXPECTED_PCEP_MESSAGE,
|
||||
EC_PATH_PCEP_UNEXPECTED_PCEPLIB_EVENT,
|
||||
EC_PATH_PCEP_UNEXPECTED_PCEP_OBJECT,
|
||||
EC_PATH_PCEP_UNEXPECTED_PCEP_TLV,
|
||||
EC_PATH_PCEP_UNEXPECTED_PCEP_ERO_SUBOBJ,
|
||||
EC_PATH_PCEP_UNEXPECTED_SR_NAI,
|
||||
EC_PATH_PCEP_COMPUTATION_REQUEST_TIMEOUT
|
||||
};
|
||||
|
||||
extern void path_error_init(void);
|
||||
|
||||
#endif
|
154
pathd/path_main.c
Normal file
154
pathd/path_main.c
Normal file
@ -0,0 +1,154 @@
|
||||
/*
|
||||
* Copyright (C) 2020 NetDEF, Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the Free
|
||||
* Software Foundation; either version 2 of the License, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; see the file COPYING; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
#include <zebra.h>
|
||||
|
||||
#include <lib/version.h>
|
||||
#include "getopt.h"
|
||||
#include "thread.h"
|
||||
#include "command.h"
|
||||
#include "log.h"
|
||||
#include "memory.h"
|
||||
#include "privs.h"
|
||||
#include "sigevent.h"
|
||||
#include "libfrr.h"
|
||||
#include "vrf.h"
|
||||
#include "filter.h"
|
||||
|
||||
#include "pathd.h"
|
||||
#include "path_nb.h"
|
||||
#include "path_zebra.h"
|
||||
#include "path_errors.h"
|
||||
|
||||
char backup_config_file[256];
|
||||
|
||||
zebra_capabilities_t _caps_p[] = {};
|
||||
|
||||
struct zebra_privs_t pathd_privs = {
|
||||
#if defined(FRR_USER) && defined(FRR_GROUP)
|
||||
.user = FRR_USER,
|
||||
.group = FRR_GROUP,
|
||||
#endif
|
||||
#if defined(VTY_GROUP)
|
||||
.vty_group = VTY_GROUP,
|
||||
#endif
|
||||
.caps_p = _caps_p,
|
||||
.cap_num_p = array_size(_caps_p),
|
||||
.cap_num_i = 0};
|
||||
|
||||
struct option longopts[] = {{0}};
|
||||
|
||||
/* Master of threads. */
|
||||
struct thread_master *master;
|
||||
|
||||
static struct frr_daemon_info pathd_di;
|
||||
|
||||
/* SIGHUP handler. */
|
||||
static void sighup(void)
|
||||
{
|
||||
zlog_info("SIGHUP received");
|
||||
|
||||
/* Reload config file. */
|
||||
vty_read_config(NULL, pathd_di.config_file, config_default);
|
||||
}
|
||||
|
||||
/* SIGINT / SIGTERM handler. */
|
||||
static void sigint(void)
|
||||
{
|
||||
zlog_notice("Terminating on signal");
|
||||
|
||||
exit(0);
|
||||
}
|
||||
|
||||
/* SIGUSR1 handler. */
|
||||
static void sigusr1(void)
|
||||
{
|
||||
zlog_rotate();
|
||||
}
|
||||
|
||||
struct quagga_signal_t path_signals[] = {
|
||||
{
|
||||
.signal = SIGHUP,
|
||||
.handler = &sighup,
|
||||
},
|
||||
{
|
||||
.signal = SIGUSR1,
|
||||
.handler = &sigusr1,
|
||||
},
|
||||
{
|
||||
.signal = SIGINT,
|
||||
.handler = &sigint,
|
||||
},
|
||||
{
|
||||
.signal = SIGTERM,
|
||||
.handler = &sigint,
|
||||
},
|
||||
};
|
||||
|
||||
static const struct frr_yang_module_info *pathd_yang_modules[] = {
|
||||
&frr_filter_info,
|
||||
&frr_interface_info,
|
||||
&frr_pathd_info,
|
||||
};
|
||||
|
||||
#define PATH_VTY_PORT 2621
|
||||
|
||||
FRR_DAEMON_INFO(pathd, PATH, .vty_port = PATH_VTY_PORT,
|
||||
|
||||
.proghelp = "Implementation of PATH.",
|
||||
|
||||
.signals = path_signals, .n_signals = array_size(path_signals),
|
||||
|
||||
.privs = &pathd_privs, .yang_modules = pathd_yang_modules,
|
||||
.n_yang_modules = array_size(pathd_yang_modules), )
|
||||
|
||||
int main(int argc, char **argv, char **envp)
|
||||
{
|
||||
frr_preinit(&pathd_di, argc, argv);
|
||||
frr_opt_add("", longopts, "");
|
||||
|
||||
while (1) {
|
||||
int opt;
|
||||
|
||||
opt = frr_getopt(argc, argv, NULL);
|
||||
|
||||
if (opt == EOF)
|
||||
break;
|
||||
|
||||
switch (opt) {
|
||||
case 0:
|
||||
break;
|
||||
default:
|
||||
frr_help_exit(1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
master = frr_init();
|
||||
|
||||
access_list_init();
|
||||
|
||||
path_error_init();
|
||||
path_zebra_init(master);
|
||||
path_cli_init();
|
||||
|
||||
frr_config_fork();
|
||||
frr_run(master);
|
||||
|
||||
/* Not reached. */
|
||||
return 0;
|
||||
}
|
25
pathd/path_memory.c
Normal file
25
pathd/path_memory.c
Normal file
@ -0,0 +1,25 @@
|
||||
/*
|
||||
* Copyright (C) 2020 NetDEF, Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the Free
|
||||
* Software Foundation; either version 2 of the License, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; see the file COPYING; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include <zebra.h>
|
||||
|
||||
#include <memory.h>
|
||||
|
||||
#include "pathd/path_memory.h"
|
||||
|
||||
DEFINE_MGROUP(PATHD, "pathd")
|
26
pathd/path_memory.h
Normal file
26
pathd/path_memory.h
Normal file
@ -0,0 +1,26 @@
|
||||
/*
|
||||
* Copyright (C) 2020 NetDEF, Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the Free
|
||||
* Software Foundation; either version 2 of the License, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; see the file COPYING; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#ifndef _FRR_PATH_MEMORY_H_
|
||||
#define _FRR_PATH_MEMORY_H_
|
||||
|
||||
#include "memory.h"
|
||||
|
||||
DECLARE_MGROUP(PATHD)
|
||||
|
||||
#endif /* _FRR_PATH_MEMORY_H_ */
|
351
pathd/path_nb.c
Normal file
351
pathd/path_nb.c
Normal file
@ -0,0 +1,351 @@
|
||||
/*
|
||||
* Copyright (C) 2020 NetDEF, Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the Free
|
||||
* Software Foundation; either version 2 of the License, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; see the file COPYING; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include <zebra.h>
|
||||
|
||||
#include "northbound.h"
|
||||
#include "libfrr.h"
|
||||
|
||||
#include "pathd/path_nb.h"
|
||||
|
||||
static int iter_objfun_cb(const struct lyd_node *dnode, void *arg);
|
||||
static int dummy_create(struct nb_cb_create_args *args);
|
||||
static int dummy_modify(struct nb_cb_modify_args *args);
|
||||
static int dummy_destroy(struct nb_cb_destroy_args *args);
|
||||
|
||||
struct of_cb_pref {
|
||||
uint32_t index;
|
||||
enum objfun_type type;
|
||||
struct of_cb_pref *next;
|
||||
};
|
||||
|
||||
struct of_cb_args {
|
||||
struct of_cb_pref *first;
|
||||
uint32_t free_slot;
|
||||
struct of_cb_pref prefs[MAX_OBJFUN_TYPE];
|
||||
};
|
||||
|
||||
/* clang-format off */
|
||||
const struct frr_yang_module_info frr_pathd_info = {
|
||||
.name = "frr-pathd",
|
||||
.nodes = {
|
||||
{
|
||||
.xpath = "/frr-pathd:pathd",
|
||||
.cbs = {
|
||||
.apply_finish = pathd_apply_finish,
|
||||
},
|
||||
.priority = NB_DFLT_PRIORITY + 1
|
||||
},
|
||||
{
|
||||
.xpath = "/frr-pathd:pathd/srte/segment-list",
|
||||
.cbs = {
|
||||
.create = pathd_srte_segment_list_create,
|
||||
.cli_show = cli_show_srte_segment_list,
|
||||
.destroy = pathd_srte_segment_list_destroy,
|
||||
.get_next = pathd_srte_segment_list_get_next,
|
||||
.get_keys = pathd_srte_segment_list_get_keys,
|
||||
.lookup_entry = pathd_srte_segment_list_lookup_entry,
|
||||
},
|
||||
.priority = NB_DFLT_PRIORITY - 1
|
||||
},
|
||||
{
|
||||
.xpath = "/frr-pathd:pathd/srte/segment-list/protocol-origin",
|
||||
.cbs = {
|
||||
.modify = pathd_srte_segment_list_protocol_origin_modify,
|
||||
},
|
||||
.priority = NB_DFLT_PRIORITY - 1
|
||||
},
|
||||
{
|
||||
.xpath = "/frr-pathd:pathd/srte/segment-list/originator",
|
||||
.cbs = {
|
||||
.modify = pathd_srte_segment_list_originator_modify,
|
||||
},
|
||||
.priority = NB_DFLT_PRIORITY - 1
|
||||
},
|
||||
{
|
||||
.xpath = "/frr-pathd:pathd/srte/segment-list/segment",
|
||||
.cbs = {
|
||||
.create = pathd_srte_segment_list_segment_create,
|
||||
.cli_show = cli_show_srte_segment_list_segment,
|
||||
.destroy = pathd_srte_segment_list_segment_destroy,
|
||||
},
|
||||
.priority = NB_DFLT_PRIORITY - 1
|
||||
},
|
||||
{
|
||||
.xpath = "/frr-pathd:pathd/srte/segment-list/segment/sid-value",
|
||||
.cbs = {
|
||||
.modify = pathd_srte_segment_list_segment_sid_value_modify,
|
||||
},
|
||||
.priority = NB_DFLT_PRIORITY - 1
|
||||
},
|
||||
{
|
||||
.xpath = "/frr-pathd:pathd/srte/segment-list/segment/nai",
|
||||
.cbs = {
|
||||
.create = dummy_create,
|
||||
.destroy = pathd_srte_segment_list_segment_nai_destroy,
|
||||
.apply_finish = pathd_srte_segment_list_segment_nai_apply_finish
|
||||
},
|
||||
.priority = NB_DFLT_PRIORITY - 1
|
||||
},
|
||||
{
|
||||
.xpath = "/frr-pathd:pathd/srte/segment-list/segment/nai/type",
|
||||
.cbs = {.modify = dummy_modify}
|
||||
},
|
||||
{
|
||||
.xpath = "/frr-pathd:pathd/srte/segment-list/segment/nai/local-address",
|
||||
.cbs = {.modify = dummy_modify}
|
||||
},
|
||||
{
|
||||
.xpath = "/frr-pathd:pathd/srte/segment-list/segment/nai/local-interface",
|
||||
.cbs = {.modify = dummy_modify, .destroy = dummy_destroy}
|
||||
},
|
||||
{
|
||||
.xpath = "/frr-pathd:pathd/srte/segment-list/segment/nai/remote-address",
|
||||
.cbs = {.modify = dummy_modify, .destroy = dummy_destroy}
|
||||
},
|
||||
{
|
||||
.xpath = "/frr-pathd:pathd/srte/segment-list/segment/nai/remote-interface",
|
||||
.cbs = {.modify = dummy_modify, .destroy = dummy_destroy}
|
||||
},
|
||||
{
|
||||
.xpath = "/frr-pathd:pathd/srte/policy",
|
||||
.cbs = {
|
||||
.create = pathd_srte_policy_create,
|
||||
.cli_show = cli_show_srte_policy,
|
||||
.destroy = pathd_srte_policy_destroy,
|
||||
.get_next = pathd_srte_policy_get_next,
|
||||
.get_keys = pathd_srte_policy_get_keys,
|
||||
.lookup_entry = pathd_srte_policy_lookup_entry,
|
||||
}
|
||||
},
|
||||
{
|
||||
.xpath = "/frr-pathd:pathd/srte/policy/name",
|
||||
.cbs = {
|
||||
.modify = pathd_srte_policy_name_modify,
|
||||
.cli_show = cli_show_srte_policy_name,
|
||||
.destroy = pathd_srte_policy_name_destroy,
|
||||
}
|
||||
},
|
||||
{
|
||||
.xpath = "/frr-pathd:pathd/srte/policy/binding-sid",
|
||||
.cbs = {
|
||||
.modify = pathd_srte_policy_binding_sid_modify,
|
||||
.cli_show = cli_show_srte_policy_binding_sid,
|
||||
.destroy = pathd_srte_policy_binding_sid_destroy,
|
||||
}
|
||||
},
|
||||
{
|
||||
.xpath = "/frr-pathd:pathd/srte/policy/is-operational",
|
||||
.cbs = {
|
||||
.get_elem = pathd_srte_policy_is_operational_get_elem
|
||||
}
|
||||
},
|
||||
{
|
||||
.xpath = "/frr-pathd:pathd/srte/policy/candidate-path",
|
||||
.cbs = {
|
||||
.create = pathd_srte_policy_candidate_path_create,
|
||||
.cli_show = cli_show_srte_policy_candidate_path,
|
||||
.destroy = pathd_srte_policy_candidate_path_destroy,
|
||||
.get_next = pathd_srte_policy_candidate_path_get_next,
|
||||
.get_keys = pathd_srte_policy_candidate_path_get_keys,
|
||||
.lookup_entry = pathd_srte_policy_candidate_path_lookup_entry,
|
||||
}
|
||||
},
|
||||
{
|
||||
.xpath = "/frr-pathd:pathd/srte/policy/candidate-path/name",
|
||||
.cbs = {
|
||||
.modify = pathd_srte_policy_candidate_path_name_modify,
|
||||
}
|
||||
},
|
||||
{
|
||||
.xpath = "/frr-pathd:pathd/srte/policy/candidate-path/is-best-candidate-path",
|
||||
.cbs = {
|
||||
.get_elem = pathd_srte_policy_candidate_path_is_best_candidate_path_get_elem,
|
||||
}
|
||||
},
|
||||
{
|
||||
.xpath = "/frr-pathd:pathd/srte/policy/candidate-path/protocol-origin",
|
||||
.cbs = {
|
||||
.modify = pathd_srte_policy_candidate_path_protocol_origin_modify,
|
||||
}
|
||||
},
|
||||
{
|
||||
.xpath = "/frr-pathd:pathd/srte/policy/candidate-path/originator",
|
||||
.cbs = {
|
||||
.modify = pathd_srte_policy_candidate_path_originator_modify,
|
||||
}
|
||||
},
|
||||
{
|
||||
.xpath = "/frr-pathd:pathd/srte/policy/candidate-path/discriminator",
|
||||
.cbs = {
|
||||
.get_elem = pathd_srte_policy_candidate_path_discriminator_get_elem,
|
||||
}
|
||||
},
|
||||
{
|
||||
.xpath = "/frr-pathd:pathd/srte/policy/candidate-path/type",
|
||||
.cbs = {
|
||||
.modify = pathd_srte_policy_candidate_path_type_modify,
|
||||
}
|
||||
},
|
||||
{
|
||||
.xpath = "/frr-pathd:pathd/srte/policy/candidate-path/segment-list-name",
|
||||
.cbs = {
|
||||
.destroy = pathd_srte_policy_candidate_path_segment_list_name_destroy,
|
||||
.modify = pathd_srte_policy_candidate_path_segment_list_name_modify,
|
||||
}
|
||||
},
|
||||
{
|
||||
.xpath = "/frr-pathd:pathd/srte/policy/candidate-path/constraints/bandwidth",
|
||||
.cbs = {
|
||||
.create = dummy_create,
|
||||
.destroy = pathd_srte_policy_candidate_path_bandwidth_destroy,
|
||||
.apply_finish = pathd_srte_policy_candidate_path_bandwidth_apply_finish
|
||||
}
|
||||
},
|
||||
{
|
||||
.xpath = "/frr-pathd:pathd/srte/policy/candidate-path/constraints/bandwidth/required",
|
||||
.cbs = {.modify = dummy_modify}
|
||||
},
|
||||
{
|
||||
.xpath = "/frr-pathd:pathd/srte/policy/candidate-path/constraints/bandwidth/value",
|
||||
.cbs = {.modify = dummy_modify}
|
||||
},
|
||||
{
|
||||
.xpath = "/frr-pathd:pathd/srte/policy/candidate-path/constraints/affinity/exclude-any",
|
||||
.cbs = {
|
||||
.modify = pathd_srte_policy_candidate_path_exclude_any_modify,
|
||||
.destroy = pathd_srte_policy_candidate_path_exclude_any_destroy,
|
||||
}
|
||||
},
|
||||
{
|
||||
.xpath = "/frr-pathd:pathd/srte/policy/candidate-path/constraints/affinity/include-any",
|
||||
.cbs = {
|
||||
.modify = pathd_srte_policy_candidate_path_include_any_modify,
|
||||
.destroy = pathd_srte_policy_candidate_path_include_any_destroy,
|
||||
}
|
||||
},
|
||||
{
|
||||
.xpath = "/frr-pathd:pathd/srte/policy/candidate-path/constraints/affinity/include-all",
|
||||
.cbs = {
|
||||
.modify = pathd_srte_policy_candidate_path_include_all_modify,
|
||||
.destroy = pathd_srte_policy_candidate_path_include_all_destroy,
|
||||
}
|
||||
},
|
||||
{
|
||||
.xpath = "/frr-pathd:pathd/srte/policy/candidate-path/constraints/metrics",
|
||||
.cbs = {
|
||||
.create = dummy_create,
|
||||
.destroy = pathd_srte_policy_candidate_path_metrics_destroy,
|
||||
.apply_finish = pathd_srte_policy_candidate_path_metrics_apply_finish
|
||||
}
|
||||
},
|
||||
{
|
||||
.xpath = "/frr-pathd:pathd/srte/policy/candidate-path/constraints/metrics/value",
|
||||
.cbs = {.modify = dummy_modify}
|
||||
},
|
||||
{
|
||||
.xpath = "/frr-pathd:pathd/srte/policy/candidate-path/constraints/metrics/required",
|
||||
.cbs = {.modify = dummy_modify}
|
||||
},
|
||||
{
|
||||
.xpath = "/frr-pathd:pathd/srte/policy/candidate-path/constraints/metrics/is-bound",
|
||||
.cbs = {.modify = dummy_modify, .destroy = dummy_destroy}
|
||||
},
|
||||
{
|
||||
.xpath = "/frr-pathd:pathd/srte/policy/candidate-path/constraints/metrics/is-computed",
|
||||
.cbs = {.modify = dummy_modify, .destroy = dummy_destroy}
|
||||
},
|
||||
{
|
||||
.xpath = "/frr-pathd:pathd/srte/policy/candidate-path/constraints/objective-function",
|
||||
.cbs = {
|
||||
.create = dummy_create,
|
||||
.destroy = pathd_srte_policy_candidate_path_objfun_destroy,
|
||||
.apply_finish = pathd_srte_policy_candidate_path_objfun_apply_finish
|
||||
}
|
||||
},
|
||||
{
|
||||
.xpath = "/frr-pathd:pathd/srte/policy/candidate-path/constraints/objective-function/required",
|
||||
.cbs = {.modify = dummy_modify}
|
||||
},
|
||||
{
|
||||
.xpath = "/frr-pathd:pathd/srte/policy/candidate-path/constraints/objective-function/type",
|
||||
.cbs = {.modify = dummy_modify}
|
||||
},
|
||||
{
|
||||
.xpath = NULL,
|
||||
},
|
||||
}
|
||||
};
|
||||
|
||||
void iter_objfun_prefs(const struct lyd_node *dnode, const char* path,
|
||||
of_pref_cp_t fun, void *arg)
|
||||
{
|
||||
struct of_cb_args args = {0};
|
||||
struct of_cb_pref *p;
|
||||
|
||||
yang_dnode_iterate(iter_objfun_cb, &args, dnode, path);
|
||||
for (p = args.first; p != NULL; p = p->next)
|
||||
fun(p->type, arg);
|
||||
}
|
||||
|
||||
int iter_objfun_cb(const struct lyd_node *dnode, void *arg)
|
||||
{
|
||||
struct of_cb_args *of_arg = arg;
|
||||
struct of_cb_pref *pref;
|
||||
struct of_cb_pref **p;
|
||||
|
||||
if (of_arg->free_slot >= MAX_OBJFUN_TYPE)
|
||||
return YANG_ITER_STOP;
|
||||
|
||||
pref = &of_arg->prefs[of_arg->free_slot++];
|
||||
|
||||
pref->index = yang_dnode_get_uint32(dnode, "./index");
|
||||
pref->type = yang_dnode_get_enum(dnode, "./type");
|
||||
|
||||
/* Simplistic insertion sort */
|
||||
p = &of_arg->first;
|
||||
while (true) {
|
||||
if (*p == NULL) {
|
||||
*p = pref;
|
||||
break;
|
||||
}
|
||||
if ((*p)->index >= pref->index) {
|
||||
pref->next = *p;
|
||||
*p = pref;
|
||||
break;
|
||||
}
|
||||
p = &(*p)->next;
|
||||
}
|
||||
|
||||
return YANG_ITER_CONTINUE;
|
||||
}
|
||||
|
||||
int dummy_create(struct nb_cb_create_args *args)
|
||||
{
|
||||
return NB_OK;
|
||||
}
|
||||
|
||||
int dummy_modify(struct nb_cb_modify_args *args)
|
||||
{
|
||||
return NB_OK;
|
||||
}
|
||||
|
||||
int dummy_destroy(struct nb_cb_destroy_args *args)
|
||||
{
|
||||
return NB_OK;
|
||||
}
|
130
pathd/path_nb.h
Normal file
130
pathd/path_nb.h
Normal file
@ -0,0 +1,130 @@
|
||||
/*
|
||||
* Copyright (C) 2020 NetDEF, Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the Free
|
||||
* Software Foundation; either version 2 of the License, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; see the file COPYING; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#ifndef _FRR_PATH_NB_H_
|
||||
#define _FRR_PATH_NB_H_
|
||||
|
||||
#include "pathd/pathd.h"
|
||||
|
||||
extern const struct frr_yang_module_info frr_pathd_info;
|
||||
|
||||
/* Mandatory callbacks. */
|
||||
int pathd_srte_segment_list_create(struct nb_cb_create_args *args);
|
||||
int pathd_srte_segment_list_destroy(struct nb_cb_destroy_args *args);
|
||||
|
||||
const void *pathd_srte_segment_list_get_next(struct nb_cb_get_next_args *args);
|
||||
int pathd_srte_segment_list_get_keys(struct nb_cb_get_keys_args *args);
|
||||
const void *
|
||||
pathd_srte_segment_list_lookup_entry(struct nb_cb_lookup_entry_args *args);
|
||||
|
||||
int pathd_srte_segment_list_segment_create(struct nb_cb_create_args *args);
|
||||
int pathd_srte_segment_list_segment_destroy(struct nb_cb_destroy_args *args);
|
||||
int pathd_srte_segment_list_protocol_origin_modify(
|
||||
struct nb_cb_modify_args *args);
|
||||
int pathd_srte_segment_list_originator_modify(struct nb_cb_modify_args *args);
|
||||
int pathd_srte_segment_list_segment_sid_value_modify(
|
||||
struct nb_cb_modify_args *args);
|
||||
int pathd_srte_segment_list_segment_nai_destroy(
|
||||
struct nb_cb_destroy_args *args);
|
||||
void pathd_srte_segment_list_segment_nai_apply_finish(
|
||||
struct nb_cb_apply_finish_args *args);
|
||||
int pathd_srte_policy_create(struct nb_cb_create_args *args);
|
||||
int pathd_srte_policy_destroy(struct nb_cb_destroy_args *args);
|
||||
const void *pathd_srte_policy_get_next(struct nb_cb_get_next_args *args);
|
||||
int pathd_srte_policy_get_keys(struct nb_cb_get_keys_args *args);
|
||||
const void *
|
||||
pathd_srte_policy_lookup_entry(struct nb_cb_lookup_entry_args *args);
|
||||
int pathd_srte_policy_name_modify(struct nb_cb_modify_args *args);
|
||||
int pathd_srte_policy_name_destroy(struct nb_cb_destroy_args *args);
|
||||
int pathd_srte_policy_binding_sid_modify(struct nb_cb_modify_args *args);
|
||||
int pathd_srte_policy_binding_sid_destroy(struct nb_cb_destroy_args *args);
|
||||
struct yang_data *
|
||||
pathd_srte_policy_is_operational_get_elem(struct nb_cb_get_elem_args *args);
|
||||
int pathd_srte_policy_candidate_path_create(struct nb_cb_create_args *args);
|
||||
int pathd_srte_policy_candidate_path_destroy(struct nb_cb_destroy_args *args);
|
||||
int pathd_srte_policy_candidate_path_name_modify(
|
||||
struct nb_cb_modify_args *args);
|
||||
const void *
|
||||
pathd_srte_policy_candidate_path_get_next(struct nb_cb_get_next_args *args);
|
||||
int pathd_srte_policy_candidate_path_get_keys(struct nb_cb_get_keys_args *args);
|
||||
const void *pathd_srte_policy_candidate_path_lookup_entry(
|
||||
struct nb_cb_lookup_entry_args *args);
|
||||
void pathd_srte_policy_candidate_path_bandwidth_apply_finish(
|
||||
struct nb_cb_apply_finish_args *args);
|
||||
int pathd_srte_policy_candidate_path_bandwidth_destroy(
|
||||
struct nb_cb_destroy_args *args);
|
||||
int pathd_srte_policy_candidate_path_exclude_any_modify(
|
||||
struct nb_cb_modify_args *args);
|
||||
int pathd_srte_policy_candidate_path_exclude_any_destroy(
|
||||
struct nb_cb_destroy_args *args);
|
||||
int pathd_srte_policy_candidate_path_include_any_modify(
|
||||
struct nb_cb_modify_args *args);
|
||||
int pathd_srte_policy_candidate_path_include_any_destroy(
|
||||
struct nb_cb_destroy_args *args);
|
||||
int pathd_srte_policy_candidate_path_include_all_modify(
|
||||
struct nb_cb_modify_args *args);
|
||||
int pathd_srte_policy_candidate_path_include_all_destroy(
|
||||
struct nb_cb_destroy_args *args);
|
||||
int pathd_srte_policy_candidate_path_metrics_destroy(
|
||||
struct nb_cb_destroy_args *args);
|
||||
void pathd_srte_policy_candidate_path_metrics_apply_finish(
|
||||
struct nb_cb_apply_finish_args *args);
|
||||
int pathd_srte_policy_candidate_path_objfun_destroy(
|
||||
struct nb_cb_destroy_args *args);
|
||||
void pathd_srte_policy_candidate_path_objfun_apply_finish(
|
||||
struct nb_cb_apply_finish_args *args);
|
||||
struct yang_data *
|
||||
pathd_srte_policy_candidate_path_is_best_candidate_path_get_elem(
|
||||
struct nb_cb_get_elem_args *args);
|
||||
int pathd_srte_policy_candidate_path_protocol_origin_modify(
|
||||
struct nb_cb_modify_args *args);
|
||||
int pathd_srte_policy_candidate_path_originator_modify(
|
||||
struct nb_cb_modify_args *args);
|
||||
struct yang_data *pathd_srte_policy_candidate_path_discriminator_get_elem(
|
||||
struct nb_cb_get_elem_args *args);
|
||||
int pathd_srte_policy_candidate_path_type_modify(
|
||||
struct nb_cb_modify_args *args);
|
||||
int pathd_srte_policy_candidate_path_segment_list_name_modify(
|
||||
struct nb_cb_modify_args *args);
|
||||
int pathd_srte_policy_candidate_path_segment_list_name_destroy(
|
||||
struct nb_cb_destroy_args *args);
|
||||
|
||||
/* Optional 'apply_finish' callbacks. */
|
||||
void pathd_apply_finish(struct nb_cb_apply_finish_args *args);
|
||||
|
||||
/* Optional 'cli_show' callbacks. */
|
||||
void cli_show_srte_segment_list(struct vty *vty, struct lyd_node *dnode,
|
||||
bool show_defaults);
|
||||
void cli_show_srte_segment_list_segment(struct vty *vty, struct lyd_node *dnode,
|
||||
bool show_defaults);
|
||||
void cli_show_srte_policy(struct vty *vty, struct lyd_node *dnode,
|
||||
bool show_defaults);
|
||||
void cli_show_srte_policy_name(struct vty *vty, struct lyd_node *dnode,
|
||||
bool show_defaults);
|
||||
void cli_show_srte_policy_binding_sid(struct vty *vty, struct lyd_node *dnode,
|
||||
bool show_defaults);
|
||||
void cli_show_srte_policy_candidate_path(struct vty *vty,
|
||||
struct lyd_node *dnode,
|
||||
bool show_defaults);
|
||||
|
||||
/* Utility functions */
|
||||
typedef void (*of_pref_cp_t)(enum objfun_type type, void *arg);
|
||||
void iter_objfun_prefs(const struct lyd_node *dnode, const char *path,
|
||||
of_pref_cp_t fun, void *arg);
|
||||
|
||||
#endif /* _FRR_PATH_NB_H_ */
|
731
pathd/path_nb_config.c
Normal file
731
pathd/path_nb_config.c
Normal file
@ -0,0 +1,731 @@
|
||||
/*
|
||||
* Copyright (C) 2020 NetDEF, Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the Free
|
||||
* Software Foundation; either version 2 of the License, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; see the file COPYING; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include <zebra.h>
|
||||
#include <lib_errors.h>
|
||||
|
||||
#include "northbound.h"
|
||||
#include "libfrr.h"
|
||||
|
||||
#include "pathd/path_zebra.h"
|
||||
#include "pathd/path_nb.h"
|
||||
|
||||
/*
|
||||
* XPath: /frr-pathd:pathd
|
||||
*/
|
||||
void pathd_apply_finish(struct nb_cb_apply_finish_args *args)
|
||||
{
|
||||
srte_apply_changes();
|
||||
}
|
||||
|
||||
/*
|
||||
* XPath: /frr-pathd:pathd/srte/segment-list
|
||||
*/
|
||||
int pathd_srte_segment_list_create(struct nb_cb_create_args *args)
|
||||
{
|
||||
struct srte_segment_list *segment_list;
|
||||
const char *name;
|
||||
|
||||
if (args->event != NB_EV_APPLY)
|
||||
return NB_OK;
|
||||
|
||||
name = yang_dnode_get_string(args->dnode, "./name");
|
||||
segment_list = srte_segment_list_add(name);
|
||||
nb_running_set_entry(args->dnode, segment_list);
|
||||
SET_FLAG(segment_list->flags, F_SEGMENT_LIST_NEW);
|
||||
|
||||
return NB_OK;
|
||||
}
|
||||
|
||||
int pathd_srte_segment_list_destroy(struct nb_cb_destroy_args *args)
|
||||
{
|
||||
struct srte_segment_list *segment_list;
|
||||
|
||||
if (args->event != NB_EV_APPLY)
|
||||
return NB_OK;
|
||||
|
||||
segment_list = nb_running_unset_entry(args->dnode);
|
||||
SET_FLAG(segment_list->flags, F_SEGMENT_LIST_DELETED);
|
||||
|
||||
return NB_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
* XPath: /frr-pathd:pathd/srte/segment-list/protocol-origin
|
||||
*/
|
||||
int pathd_srte_segment_list_protocol_origin_modify(
|
||||
struct nb_cb_modify_args *args)
|
||||
{
|
||||
struct srte_segment_list *segment_list;
|
||||
|
||||
if (args->event != NB_EV_APPLY)
|
||||
return NB_OK;
|
||||
|
||||
segment_list = nb_running_get_entry(args->dnode, NULL, true);
|
||||
segment_list->protocol_origin = yang_dnode_get_enum(args->dnode, NULL);
|
||||
SET_FLAG(segment_list->flags, F_SEGMENT_LIST_MODIFIED);
|
||||
|
||||
return NB_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
* XPath: /frr-pathd:pathd/srte/segment-list/originator
|
||||
*/
|
||||
int pathd_srte_segment_list_originator_modify(struct nb_cb_modify_args *args)
|
||||
{
|
||||
struct srte_segment_list *segment_list;
|
||||
const char *originator;
|
||||
|
||||
if (args->event != NB_EV_APPLY)
|
||||
return NB_OK;
|
||||
|
||||
segment_list = nb_running_get_entry(args->dnode, NULL, true);
|
||||
originator = yang_dnode_get_string(args->dnode, NULL);
|
||||
strlcpy(segment_list->originator, originator,
|
||||
sizeof(segment_list->originator));
|
||||
SET_FLAG(segment_list->flags, F_SEGMENT_LIST_MODIFIED);
|
||||
|
||||
return NB_OK;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* XPath: /frr-pathd:pathd/srte/segment-list/segment
|
||||
*/
|
||||
int pathd_srte_segment_list_segment_create(struct nb_cb_create_args *args)
|
||||
{
|
||||
struct srte_segment_list *segment_list;
|
||||
struct srte_segment_entry *segment;
|
||||
uint32_t index;
|
||||
|
||||
if (args->event != NB_EV_APPLY)
|
||||
return NB_OK;
|
||||
|
||||
segment_list = nb_running_get_entry(args->dnode, NULL, true);
|
||||
index = yang_dnode_get_uint32(args->dnode, "./index");
|
||||
segment = srte_segment_entry_add(segment_list, index);
|
||||
nb_running_set_entry(args->dnode, segment);
|
||||
SET_FLAG(segment_list->flags, F_SEGMENT_LIST_MODIFIED);
|
||||
|
||||
return NB_OK;
|
||||
}
|
||||
|
||||
int pathd_srte_segment_list_segment_destroy(struct nb_cb_destroy_args *args)
|
||||
{
|
||||
struct srte_segment_entry *segment;
|
||||
|
||||
if (args->event != NB_EV_APPLY)
|
||||
return NB_OK;
|
||||
|
||||
segment = nb_running_unset_entry(args->dnode);
|
||||
SET_FLAG(segment->segment_list->flags, F_SEGMENT_LIST_MODIFIED);
|
||||
|
||||
srte_segment_entry_del(segment);
|
||||
|
||||
return NB_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
* XPath: /frr-pathd:pathd/srte/segment-list/segment/sid-value
|
||||
*/
|
||||
int pathd_srte_segment_list_segment_sid_value_modify(
|
||||
struct nb_cb_modify_args *args)
|
||||
{
|
||||
mpls_label_t sid_value;
|
||||
struct srte_segment_entry *segment;
|
||||
|
||||
if (args->event != NB_EV_APPLY)
|
||||
return NB_OK;
|
||||
|
||||
segment = nb_running_get_entry(args->dnode, NULL, true);
|
||||
sid_value = yang_dnode_get_uint32(args->dnode, NULL);
|
||||
segment->sid_value = sid_value;
|
||||
SET_FLAG(segment->segment_list->flags, F_SEGMENT_LIST_MODIFIED);
|
||||
|
||||
return NB_OK;
|
||||
}
|
||||
|
||||
int pathd_srte_segment_list_segment_nai_destroy(struct nb_cb_destroy_args *args)
|
||||
{
|
||||
struct srte_segment_entry *segment;
|
||||
|
||||
if (args->event != NB_EV_APPLY)
|
||||
return NB_OK;
|
||||
|
||||
segment = nb_running_get_entry(args->dnode, NULL, true);
|
||||
segment->nai_type = SRTE_SEGMENT_NAI_TYPE_NONE;
|
||||
segment->nai_local_addr.ipa_type = IPADDR_NONE;
|
||||
segment->nai_local_iface = 0;
|
||||
segment->nai_remote_addr.ipa_type = IPADDR_NONE;
|
||||
segment->nai_remote_iface = 0;
|
||||
|
||||
return NB_OK;
|
||||
}
|
||||
|
||||
void pathd_srte_segment_list_segment_nai_apply_finish(
|
||||
struct nb_cb_apply_finish_args *args)
|
||||
{
|
||||
struct srte_segment_entry *segment;
|
||||
enum srte_segment_nai_type type;
|
||||
struct ipaddr local_addr, remote_addr;
|
||||
uint32_t local_iface = 0, remote_iface = 0;
|
||||
|
||||
segment = nb_running_get_entry(args->dnode, NULL, true);
|
||||
type = yang_dnode_get_enum(args->dnode, "./type");
|
||||
|
||||
yang_dnode_get_ip(&local_addr, args->dnode, "./local-address");
|
||||
|
||||
switch (type) {
|
||||
case SRTE_SEGMENT_NAI_TYPE_IPV4_NODE:
|
||||
case SRTE_SEGMENT_NAI_TYPE_IPV6_NODE:
|
||||
break;
|
||||
case SRTE_SEGMENT_NAI_TYPE_IPV4_ADJACENCY:
|
||||
case SRTE_SEGMENT_NAI_TYPE_IPV6_ADJACENCY:
|
||||
yang_dnode_get_ip(&remote_addr, args->dnode,
|
||||
"./remote-address");
|
||||
break;
|
||||
case SRTE_SEGMENT_NAI_TYPE_IPV4_UNNUMBERED_ADJACENCY:
|
||||
yang_dnode_get_ip(&remote_addr, args->dnode,
|
||||
"./remote-address");
|
||||
local_iface =
|
||||
yang_dnode_get_uint32(args->dnode, "./local-interface");
|
||||
remote_iface = yang_dnode_get_uint32(args->dnode,
|
||||
"./remote-interface");
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
srte_segment_entry_set_nai(segment, type, &local_addr, local_iface,
|
||||
&remote_addr, remote_iface);
|
||||
}
|
||||
|
||||
/*
|
||||
* XPath: /frr-pathd:pathd/srte/policy
|
||||
*/
|
||||
int pathd_srte_policy_create(struct nb_cb_create_args *args)
|
||||
{
|
||||
struct srte_policy *policy;
|
||||
uint32_t color;
|
||||
struct ipaddr endpoint;
|
||||
|
||||
if (args->event != NB_EV_APPLY)
|
||||
return NB_OK;
|
||||
|
||||
color = yang_dnode_get_uint32(args->dnode, "./color");
|
||||
yang_dnode_get_ip(&endpoint, args->dnode, "./endpoint");
|
||||
policy = srte_policy_add(color, &endpoint);
|
||||
|
||||
nb_running_set_entry(args->dnode, policy);
|
||||
SET_FLAG(policy->flags, F_POLICY_NEW);
|
||||
|
||||
return NB_OK;
|
||||
}
|
||||
|
||||
int pathd_srte_policy_destroy(struct nb_cb_destroy_args *args)
|
||||
{
|
||||
struct srte_policy *policy;
|
||||
|
||||
if (args->event != NB_EV_APPLY)
|
||||
return NB_OK;
|
||||
|
||||
policy = nb_running_unset_entry(args->dnode);
|
||||
SET_FLAG(policy->flags, F_POLICY_DELETED);
|
||||
|
||||
return NB_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
* XPath: /frr-pathd:pathd/srte/policy/name
|
||||
*/
|
||||
int pathd_srte_policy_name_modify(struct nb_cb_modify_args *args)
|
||||
{
|
||||
struct srte_policy *policy;
|
||||
const char *name;
|
||||
|
||||
if (args->event != NB_EV_APPLY && args->event != NB_EV_VALIDATE)
|
||||
return NB_OK;
|
||||
|
||||
policy = nb_running_get_entry(args->dnode, NULL, true);
|
||||
|
||||
if (args->event == NB_EV_VALIDATE) {
|
||||
/* the policy name is fixed after setting it once */
|
||||
if (strlen(policy->name) > 0) {
|
||||
flog_warn(EC_LIB_NB_CB_CONFIG_VALIDATE,
|
||||
"The SR Policy name is fixed!");
|
||||
return NB_ERR_RESOURCE;
|
||||
} else
|
||||
return NB_OK;
|
||||
}
|
||||
|
||||
name = yang_dnode_get_string(args->dnode, NULL);
|
||||
strlcpy(policy->name, name, sizeof(policy->name));
|
||||
SET_FLAG(policy->flags, F_POLICY_MODIFIED);
|
||||
|
||||
return NB_OK;
|
||||
}
|
||||
|
||||
int pathd_srte_policy_name_destroy(struct nb_cb_destroy_args *args)
|
||||
{
|
||||
struct srte_policy *policy;
|
||||
|
||||
if (args->event != NB_EV_APPLY)
|
||||
return NB_OK;
|
||||
|
||||
policy = nb_running_get_entry(args->dnode, NULL, true);
|
||||
policy->name[0] = '\0';
|
||||
SET_FLAG(policy->flags, F_POLICY_MODIFIED);
|
||||
|
||||
return NB_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
* XPath: /frr-pathd:pathd/srte/policy/binding-sid
|
||||
*/
|
||||
int pathd_srte_policy_binding_sid_modify(struct nb_cb_modify_args *args)
|
||||
{
|
||||
struct srte_policy *policy;
|
||||
mpls_label_t binding_sid;
|
||||
|
||||
policy = nb_running_get_entry(args->dnode, NULL, true);
|
||||
binding_sid = yang_dnode_get_uint32(args->dnode, NULL);
|
||||
|
||||
switch (args->event) {
|
||||
case NB_EV_VALIDATE:
|
||||
break;
|
||||
case NB_EV_PREPARE:
|
||||
if (path_zebra_request_label(binding_sid) < 0)
|
||||
return NB_ERR_RESOURCE;
|
||||
break;
|
||||
case NB_EV_ABORT:
|
||||
break;
|
||||
case NB_EV_APPLY:
|
||||
srte_policy_update_binding_sid(policy, binding_sid);
|
||||
SET_FLAG(policy->flags, F_POLICY_MODIFIED);
|
||||
break;
|
||||
}
|
||||
|
||||
return NB_OK;
|
||||
}
|
||||
|
||||
int pathd_srte_policy_binding_sid_destroy(struct nb_cb_destroy_args *args)
|
||||
{
|
||||
struct srte_policy *policy;
|
||||
|
||||
if (args->event != NB_EV_APPLY)
|
||||
return NB_OK;
|
||||
|
||||
policy = nb_running_get_entry(args->dnode, NULL, true);
|
||||
srte_policy_update_binding_sid(policy, MPLS_LABEL_NONE);
|
||||
SET_FLAG(policy->flags, F_POLICY_MODIFIED);
|
||||
|
||||
return NB_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
* XPath: /frr-pathd:pathd/srte/policy/candidate-path
|
||||
*/
|
||||
int pathd_srte_policy_candidate_path_create(struct nb_cb_create_args *args)
|
||||
{
|
||||
struct srte_policy *policy;
|
||||
struct srte_candidate *candidate;
|
||||
uint32_t preference;
|
||||
|
||||
if (args->event != NB_EV_APPLY)
|
||||
return NB_OK;
|
||||
|
||||
policy = nb_running_get_entry(args->dnode, NULL, true);
|
||||
preference = yang_dnode_get_uint32(args->dnode, "./preference");
|
||||
candidate = srte_candidate_add(policy, preference);
|
||||
nb_running_set_entry(args->dnode, candidate);
|
||||
SET_FLAG(candidate->flags, F_CANDIDATE_NEW);
|
||||
|
||||
return NB_OK;
|
||||
}
|
||||
|
||||
int pathd_srte_policy_candidate_path_destroy(struct nb_cb_destroy_args *args)
|
||||
{
|
||||
struct srte_candidate *candidate;
|
||||
|
||||
if (args->event != NB_EV_APPLY)
|
||||
return NB_OK;
|
||||
|
||||
candidate = nb_running_unset_entry(args->dnode);
|
||||
SET_FLAG(candidate->flags, F_CANDIDATE_DELETED);
|
||||
|
||||
return NB_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
* XPath: /frr-pathd:pathd/srte/policy/candidate-path/name
|
||||
*/
|
||||
int pathd_srte_policy_candidate_path_name_modify(struct nb_cb_modify_args *args)
|
||||
{
|
||||
struct srte_candidate *candidate;
|
||||
const char *name;
|
||||
char xpath[XPATH_MAXLEN];
|
||||
char xpath_buf[XPATH_MAXLEN - 3];
|
||||
|
||||
if (args->event != NB_EV_APPLY && args->event != NB_EV_VALIDATE)
|
||||
return NB_OK;
|
||||
|
||||
/* the candidate name is fixed after setting it once, this is checked
|
||||
* here */
|
||||
if (args->event == NB_EV_VALIDATE) {
|
||||
/* first get the precise path to the candidate path */
|
||||
yang_dnode_get_path(args->dnode, xpath_buf, sizeof(xpath_buf));
|
||||
snprintf(xpath, sizeof(xpath), "%s%s", xpath_buf, "/..");
|
||||
|
||||
candidate = nb_running_get_entry_non_rec(NULL, xpath, false);
|
||||
|
||||
/* then check if it exists and if the name was provided */
|
||||
if (candidate && strlen(candidate->name) > 0) {
|
||||
flog_warn(EC_LIB_NB_CB_CONFIG_VALIDATE,
|
||||
"The candidate name is fixed!");
|
||||
return NB_ERR_RESOURCE;
|
||||
} else
|
||||
return NB_OK;
|
||||
}
|
||||
|
||||
candidate = nb_running_get_entry(args->dnode, NULL, true);
|
||||
|
||||
name = yang_dnode_get_string(args->dnode, NULL);
|
||||
strlcpy(candidate->name, name, sizeof(candidate->name));
|
||||
SET_FLAG(candidate->flags, F_CANDIDATE_MODIFIED);
|
||||
|
||||
return NB_OK;
|
||||
}
|
||||
|
||||
|
||||
static int affinity_filter_modify(struct nb_cb_modify_args *args,
|
||||
enum affinity_filter_type type)
|
||||
{
|
||||
uint32_t filter;
|
||||
struct srte_candidate *candidate;
|
||||
|
||||
if (args->event != NB_EV_APPLY)
|
||||
return NB_OK;
|
||||
|
||||
assert(args->context != NULL);
|
||||
candidate = nb_running_get_entry(args->dnode, NULL, true);
|
||||
filter = yang_dnode_get_uint32(args->dnode, NULL);
|
||||
srte_candidate_set_affinity_filter(candidate, type, filter);
|
||||
|
||||
return NB_OK;
|
||||
}
|
||||
|
||||
static int affinity_filter_destroy(struct nb_cb_destroy_args *args,
|
||||
enum affinity_filter_type type)
|
||||
{
|
||||
struct srte_candidate *candidate;
|
||||
|
||||
if (args->event != NB_EV_APPLY)
|
||||
return NB_OK;
|
||||
|
||||
assert(args->context != NULL);
|
||||
candidate = nb_running_get_entry(args->dnode, NULL, true);
|
||||
srte_candidate_unset_affinity_filter(candidate, type);
|
||||
|
||||
return NB_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
* XPath:
|
||||
* /frr-pathd:pathd/srte/policy/candidate-path/constraints/affinity/exclude-any
|
||||
*/
|
||||
|
||||
int pathd_srte_policy_candidate_path_exclude_any_modify(
|
||||
struct nb_cb_modify_args *args)
|
||||
{
|
||||
return affinity_filter_modify(args, AFFINITY_FILTER_EXCLUDE_ANY);
|
||||
}
|
||||
|
||||
int pathd_srte_policy_candidate_path_exclude_any_destroy(
|
||||
struct nb_cb_destroy_args *args)
|
||||
{
|
||||
return affinity_filter_destroy(args, AFFINITY_FILTER_EXCLUDE_ANY);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* XPath:
|
||||
* /frr-pathd:pathd/srte/policy/candidate-path/constraints/affinity/include-any
|
||||
*/
|
||||
int pathd_srte_policy_candidate_path_include_any_modify(
|
||||
struct nb_cb_modify_args *args)
|
||||
{
|
||||
return affinity_filter_modify(args, AFFINITY_FILTER_INCLUDE_ANY);
|
||||
}
|
||||
|
||||
int pathd_srte_policy_candidate_path_include_any_destroy(
|
||||
struct nb_cb_destroy_args *args)
|
||||
{
|
||||
return affinity_filter_destroy(args, AFFINITY_FILTER_INCLUDE_ANY);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* XPath:
|
||||
* /frr-pathd:pathd/srte/policy/candidate-path/constraints/affinity/include-all
|
||||
*/
|
||||
int pathd_srte_policy_candidate_path_include_all_modify(
|
||||
struct nb_cb_modify_args *args)
|
||||
{
|
||||
return affinity_filter_modify(args, AFFINITY_FILTER_INCLUDE_ALL);
|
||||
}
|
||||
|
||||
int pathd_srte_policy_candidate_path_include_all_destroy(
|
||||
struct nb_cb_destroy_args *args)
|
||||
{
|
||||
return affinity_filter_destroy(args, AFFINITY_FILTER_INCLUDE_ALL);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* XPath: /frr-pathd:pathd/srte/policy/candidate-path/constraints/metrics
|
||||
*/
|
||||
int pathd_srte_policy_candidate_path_metrics_destroy(
|
||||
struct nb_cb_destroy_args *args)
|
||||
{
|
||||
struct srte_candidate *candidate;
|
||||
enum srte_candidate_metric_type type;
|
||||
|
||||
if (args->event != NB_EV_APPLY)
|
||||
return NB_OK;
|
||||
|
||||
assert(args->context != NULL);
|
||||
candidate = nb_running_get_entry(args->dnode, NULL, true);
|
||||
|
||||
type = yang_dnode_get_enum(args->dnode, "./type");
|
||||
srte_candidate_unset_metric(candidate, type);
|
||||
|
||||
return NB_OK;
|
||||
}
|
||||
|
||||
void pathd_srte_policy_candidate_path_metrics_apply_finish(
|
||||
struct nb_cb_apply_finish_args *args)
|
||||
{
|
||||
struct srte_candidate *candidate;
|
||||
enum srte_candidate_metric_type type;
|
||||
float value;
|
||||
bool required, is_bound = false, is_computed = false;
|
||||
|
||||
assert(args->context != NULL);
|
||||
|
||||
candidate = nb_running_get_entry(args->dnode, NULL, true);
|
||||
|
||||
type = yang_dnode_get_enum(args->dnode, "./type");
|
||||
value = (float)yang_dnode_get_dec64(args->dnode, "./value");
|
||||
required = yang_dnode_get_bool(args->dnode, "./required");
|
||||
if (yang_dnode_exists(args->dnode, "./is-bound"))
|
||||
is_bound = yang_dnode_get_bool(args->dnode, "./is-bound");
|
||||
if (yang_dnode_exists(args->dnode, "./is-computed"))
|
||||
is_computed = yang_dnode_get_bool(args->dnode, "./is-computed");
|
||||
|
||||
srte_candidate_set_metric(candidate, type, value, required, is_bound,
|
||||
is_computed);
|
||||
}
|
||||
|
||||
/*
|
||||
* XPath:
|
||||
* /frr-pathd:pathd/srte/policy/candidate-path/constraints/objective-function
|
||||
*/
|
||||
int pathd_srte_policy_candidate_path_objfun_destroy(
|
||||
struct nb_cb_destroy_args *args)
|
||||
{
|
||||
struct srte_candidate *candidate;
|
||||
|
||||
if (args->event != NB_EV_APPLY)
|
||||
return NB_OK;
|
||||
|
||||
assert(args->context != NULL);
|
||||
|
||||
candidate = nb_running_get_entry(args->dnode, NULL, true);
|
||||
srte_candidate_unset_objfun(candidate);
|
||||
|
||||
return NB_OK;
|
||||
}
|
||||
|
||||
void pathd_srte_policy_candidate_path_objfun_apply_finish(
|
||||
struct nb_cb_apply_finish_args *args)
|
||||
{
|
||||
struct srte_candidate *candidate;
|
||||
enum objfun_type type;
|
||||
bool required;
|
||||
|
||||
candidate = nb_running_get_entry(args->dnode, NULL, true);
|
||||
required = yang_dnode_get_bool(args->dnode, "./required");
|
||||
type = yang_dnode_get_enum(args->dnode, "./type");
|
||||
srte_candidate_set_objfun(candidate, required, type);
|
||||
}
|
||||
|
||||
/*
|
||||
* XPath: /frr-pathd:pathd/srte/policy/candidate-path/protocol-origin
|
||||
*/
|
||||
int pathd_srte_policy_candidate_path_protocol_origin_modify(
|
||||
struct nb_cb_modify_args *args)
|
||||
{
|
||||
struct srte_candidate *candidate;
|
||||
enum srte_protocol_origin protocol_origin;
|
||||
|
||||
if (args->event != NB_EV_APPLY)
|
||||
return NB_OK;
|
||||
|
||||
candidate = nb_running_get_entry(args->dnode, NULL, true);
|
||||
protocol_origin = yang_dnode_get_enum(args->dnode, NULL);
|
||||
candidate->protocol_origin = protocol_origin;
|
||||
candidate->lsp->protocol_origin = protocol_origin;
|
||||
SET_FLAG(candidate->flags, F_CANDIDATE_MODIFIED);
|
||||
|
||||
return NB_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
* XPath: /frr-pathd:pathd/srte/policy/candidate-path/originator
|
||||
*/
|
||||
int pathd_srte_policy_candidate_path_originator_modify(
|
||||
struct nb_cb_modify_args *args)
|
||||
{
|
||||
struct srte_candidate *candidate;
|
||||
const char *originator;
|
||||
|
||||
if (args->event != NB_EV_APPLY)
|
||||
return NB_OK;
|
||||
|
||||
candidate = nb_running_get_entry(args->dnode, NULL, true);
|
||||
originator = yang_dnode_get_string(args->dnode, NULL);
|
||||
strlcpy(candidate->originator, originator,
|
||||
sizeof(candidate->originator));
|
||||
strlcpy(candidate->lsp->originator, originator,
|
||||
sizeof(candidate->lsp->originator));
|
||||
SET_FLAG(candidate->flags, F_CANDIDATE_MODIFIED);
|
||||
|
||||
return NB_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
* XPath: /frr-pathd:pathd/srte/policy/candidate-path/type
|
||||
*/
|
||||
int pathd_srte_policy_candidate_path_type_modify(struct nb_cb_modify_args *args)
|
||||
{
|
||||
struct srte_candidate *candidate;
|
||||
enum srte_candidate_type type;
|
||||
char xpath[XPATH_MAXLEN];
|
||||
char xpath_buf[XPATH_MAXLEN - 3];
|
||||
|
||||
if (args->event != NB_EV_APPLY && args->event != NB_EV_VALIDATE)
|
||||
return NB_OK;
|
||||
|
||||
/* the candidate type is fixed after setting it once, this is checked
|
||||
* here */
|
||||
if (args->event == NB_EV_VALIDATE) {
|
||||
/* first get the precise path to the candidate path */
|
||||
yang_dnode_get_path(args->dnode, xpath_buf, sizeof(xpath_buf));
|
||||
snprintf(xpath, sizeof(xpath), "%s%s", xpath_buf, "/..");
|
||||
|
||||
candidate = nb_running_get_entry_non_rec(NULL, xpath, false);
|
||||
|
||||
/* then check if it exists and if the type was provided */
|
||||
if (candidate
|
||||
&& candidate->type != SRTE_CANDIDATE_TYPE_UNDEFINED) {
|
||||
flog_warn(EC_LIB_NB_CB_CONFIG_VALIDATE,
|
||||
"The candidate type is fixed!");
|
||||
return NB_ERR_RESOURCE;
|
||||
} else
|
||||
return NB_OK;
|
||||
}
|
||||
|
||||
candidate = nb_running_get_entry(args->dnode, NULL, true);
|
||||
|
||||
type = yang_dnode_get_enum(args->dnode, NULL);
|
||||
candidate->type = type;
|
||||
SET_FLAG(candidate->flags, F_CANDIDATE_MODIFIED);
|
||||
|
||||
return NB_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
* XPath: /frr-pathd:pathd/srte/policy/candidate-path/segment-list-name
|
||||
*/
|
||||
int pathd_srte_policy_candidate_path_segment_list_name_modify(
|
||||
struct nb_cb_modify_args *args)
|
||||
{
|
||||
struct srte_candidate *candidate;
|
||||
const char *segment_list_name;
|
||||
|
||||
candidate = nb_running_get_entry(args->dnode, NULL, true);
|
||||
segment_list_name = yang_dnode_get_string(args->dnode, NULL);
|
||||
|
||||
if (args->event != NB_EV_APPLY)
|
||||
return NB_OK;
|
||||
|
||||
candidate->segment_list = srte_segment_list_find(segment_list_name);
|
||||
candidate->lsp->segment_list = candidate->segment_list;
|
||||
assert(candidate->segment_list);
|
||||
SET_FLAG(candidate->flags, F_CANDIDATE_MODIFIED);
|
||||
|
||||
return NB_OK;
|
||||
}
|
||||
|
||||
int pathd_srte_policy_candidate_path_segment_list_name_destroy(
|
||||
struct nb_cb_destroy_args *args)
|
||||
{
|
||||
struct srte_candidate *candidate;
|
||||
|
||||
if (args->event != NB_EV_APPLY)
|
||||
return NB_OK;
|
||||
|
||||
candidate = nb_running_get_entry(args->dnode, NULL, true);
|
||||
candidate->segment_list = NULL;
|
||||
candidate->lsp->segment_list = NULL;
|
||||
SET_FLAG(candidate->flags, F_CANDIDATE_MODIFIED);
|
||||
|
||||
return NB_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
* XPath: /frr-pathd:pathd/srte/policy/candidate-path/constraints/bandwidth
|
||||
*/
|
||||
void pathd_srte_policy_candidate_path_bandwidth_apply_finish(
|
||||
struct nb_cb_apply_finish_args *args)
|
||||
{
|
||||
struct srte_candidate *candidate;
|
||||
float value;
|
||||
bool required;
|
||||
|
||||
assert(args->context != NULL);
|
||||
|
||||
candidate = nb_running_get_entry(args->dnode, NULL, true);
|
||||
value = (float)yang_dnode_get_dec64(args->dnode, "./value");
|
||||
required = yang_dnode_get_bool(args->dnode, "./required");
|
||||
srte_candidate_set_bandwidth(candidate, value, required);
|
||||
}
|
||||
|
||||
int pathd_srte_policy_candidate_path_bandwidth_destroy(
|
||||
struct nb_cb_destroy_args *args)
|
||||
{
|
||||
struct srte_candidate *candidate;
|
||||
|
||||
if (args->event != NB_EV_APPLY)
|
||||
return NB_OK;
|
||||
|
||||
assert(args->context != NULL);
|
||||
candidate = nb_running_get_entry(args->dnode, NULL, true);
|
||||
srte_candidate_unset_bandwidth(candidate);
|
||||
return NB_OK;
|
||||
}
|
189
pathd/path_nb_state.c
Normal file
189
pathd/path_nb_state.c
Normal file
@ -0,0 +1,189 @@
|
||||
/*
|
||||
* Copyright (C) 2020 NetDEF, Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the Free
|
||||
* Software Foundation; either version 2 of the License, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; see the file COPYING; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include <zebra.h>
|
||||
|
||||
#include "log.h"
|
||||
#include "prefix.h"
|
||||
#include "table.h"
|
||||
#include "command.h"
|
||||
#include "northbound.h"
|
||||
#include "libfrr.h"
|
||||
|
||||
#include "pathd/pathd.h"
|
||||
#include "pathd/path_nb.h"
|
||||
|
||||
/*
|
||||
* XPath: /frr-pathd:pathd/srte/segment-list
|
||||
*/
|
||||
const void *pathd_srte_segment_list_get_next(struct nb_cb_get_next_args *args)
|
||||
{
|
||||
struct srte_segment_list *segment_list =
|
||||
(struct srte_segment_list *)args->list_entry;
|
||||
|
||||
if (args->list_entry == NULL)
|
||||
segment_list =
|
||||
RB_MIN(srte_segment_list_head, &srte_segment_lists);
|
||||
else
|
||||
segment_list = RB_NEXT(srte_segment_list_head, segment_list);
|
||||
|
||||
return segment_list;
|
||||
}
|
||||
|
||||
int pathd_srte_segment_list_get_keys(struct nb_cb_get_keys_args *args)
|
||||
{
|
||||
const struct srte_segment_list *segment_list =
|
||||
(struct srte_segment_list *)args->list_entry;
|
||||
|
||||
args->keys->num = 1;
|
||||
snprintf(args->keys->key[0], sizeof(args->keys->key[0]), "%s",
|
||||
segment_list->name);
|
||||
|
||||
return NB_OK;
|
||||
}
|
||||
|
||||
const void *
|
||||
pathd_srte_segment_list_lookup_entry(struct nb_cb_lookup_entry_args *args)
|
||||
{
|
||||
return srte_segment_list_find(args->keys->key[0]);
|
||||
}
|
||||
|
||||
/*
|
||||
* XPath: /frr-pathd:pathd/srte/policy
|
||||
*/
|
||||
const void *pathd_srte_policy_get_next(struct nb_cb_get_next_args *args)
|
||||
{
|
||||
struct srte_policy *policy = (struct srte_policy *)args->list_entry;
|
||||
|
||||
if (args->list_entry == NULL)
|
||||
policy = RB_MIN(srte_policy_head, &srte_policies);
|
||||
else
|
||||
policy = RB_NEXT(srte_policy_head, policy);
|
||||
|
||||
return policy;
|
||||
}
|
||||
|
||||
int pathd_srte_policy_get_keys(struct nb_cb_get_keys_args *args)
|
||||
{
|
||||
const struct srte_policy *policy =
|
||||
(struct srte_policy *)args->list_entry;
|
||||
|
||||
args->keys->num = 2;
|
||||
snprintf(args->keys->key[0], sizeof(args->keys->key[0]), "%u",
|
||||
policy->color);
|
||||
ipaddr2str(&policy->endpoint, args->keys->key[1],
|
||||
sizeof(args->keys->key[1]));
|
||||
|
||||
return NB_OK;
|
||||
}
|
||||
|
||||
const void *pathd_srte_policy_lookup_entry(struct nb_cb_lookup_entry_args *args)
|
||||
{
|
||||
uint32_t color;
|
||||
struct ipaddr endpoint;
|
||||
|
||||
color = yang_str2uint32(args->keys->key[0]);
|
||||
yang_str2ip(args->keys->key[1], &endpoint);
|
||||
|
||||
return srte_policy_find(color, &endpoint);
|
||||
}
|
||||
|
||||
/*
|
||||
* XPath: /frr-pathd:pathd/srte/policy/is-operational
|
||||
*/
|
||||
struct yang_data *
|
||||
pathd_srte_policy_is_operational_get_elem(struct nb_cb_get_elem_args *args)
|
||||
{
|
||||
struct srte_policy *policy = (struct srte_policy *)args->list_entry;
|
||||
bool is_operational = false;
|
||||
|
||||
if (policy->status == SRTE_POLICY_STATUS_UP)
|
||||
is_operational = true;
|
||||
|
||||
return yang_data_new_bool(args->xpath, is_operational);
|
||||
}
|
||||
|
||||
/*
|
||||
* XPath: /frr-pathd:pathd/srte/policy/candidate-path
|
||||
*/
|
||||
const void *
|
||||
pathd_srte_policy_candidate_path_get_next(struct nb_cb_get_next_args *args)
|
||||
{
|
||||
struct srte_policy *policy =
|
||||
(struct srte_policy *)args->parent_list_entry;
|
||||
struct srte_candidate *candidate =
|
||||
(struct srte_candidate *)args->list_entry;
|
||||
|
||||
if (args->list_entry == NULL)
|
||||
candidate =
|
||||
RB_MIN(srte_candidate_head, &policy->candidate_paths);
|
||||
else
|
||||
candidate = RB_NEXT(srte_candidate_head, candidate);
|
||||
|
||||
return candidate;
|
||||
}
|
||||
|
||||
int pathd_srte_policy_candidate_path_get_keys(struct nb_cb_get_keys_args *args)
|
||||
{
|
||||
const struct srte_candidate *candidate =
|
||||
(struct srte_candidate *)args->list_entry;
|
||||
|
||||
args->keys->num = 1;
|
||||
snprintf(args->keys->key[0], sizeof(args->keys->key[0]), "%u",
|
||||
candidate->preference);
|
||||
|
||||
return NB_OK;
|
||||
}
|
||||
|
||||
const void *pathd_srte_policy_candidate_path_lookup_entry(
|
||||
struct nb_cb_lookup_entry_args *args)
|
||||
{
|
||||
struct srte_policy *policy =
|
||||
(struct srte_policy *)args->parent_list_entry;
|
||||
uint32_t preference;
|
||||
|
||||
preference = yang_str2uint32(args->keys->key[0]);
|
||||
|
||||
return srte_candidate_find(policy, preference);
|
||||
}
|
||||
|
||||
/*
|
||||
* XPath: /frr-pathd:pathd/srte/policy/candidate_path/is-best-candidate-path
|
||||
*/
|
||||
struct yang_data *
|
||||
pathd_srte_policy_candidate_path_is_best_candidate_path_get_elem(
|
||||
struct nb_cb_get_elem_args *args)
|
||||
{
|
||||
struct srte_candidate *candidate =
|
||||
(struct srte_candidate *)args->list_entry;
|
||||
|
||||
return yang_data_new_bool(
|
||||
args->xpath, CHECK_FLAG(candidate->flags, F_CANDIDATE_BEST));
|
||||
}
|
||||
|
||||
/*
|
||||
* XPath: /frr-pathd:pathd/srte/policy/candidate-path/discriminator
|
||||
*/
|
||||
struct yang_data *pathd_srte_policy_candidate_path_discriminator_get_elem(
|
||||
struct nb_cb_get_elem_args *args)
|
||||
{
|
||||
struct srte_candidate *candidate =
|
||||
(struct srte_candidate *)args->list_entry;
|
||||
|
||||
return yang_data_new_uint32(args->xpath, candidate->discriminator);
|
||||
}
|
339
pathd/path_pcep.c
Normal file
339
pathd/path_pcep.c
Normal file
@ -0,0 +1,339 @@
|
||||
/*
|
||||
* Copyright (C) 2020 NetDEF, Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the Free
|
||||
* Software Foundation; either version 2 of the License, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; see the file COPYING; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include <zebra.h>
|
||||
#include <pcep_utils_counters.h>
|
||||
|
||||
#include "log.h"
|
||||
#include "command.h"
|
||||
#include "libfrr.h"
|
||||
#include "printfrr.h"
|
||||
#include "version.h"
|
||||
#include "northbound.h"
|
||||
#include "frr_pthread.h"
|
||||
#include "jhash.h"
|
||||
#include "termtable.h"
|
||||
|
||||
#include "pathd/pathd.h"
|
||||
#include "pathd/path_errors.h"
|
||||
#include "pathd/path_pcep_memory.h"
|
||||
#include "pathd/path_pcep.h"
|
||||
#include "pathd/path_pcep_cli.h"
|
||||
#include "pathd/path_pcep_controller.h"
|
||||
#include "pathd/path_pcep_lib.h"
|
||||
#include "pathd/path_pcep_config.h"
|
||||
|
||||
|
||||
/*
|
||||
* Globals.
|
||||
*/
|
||||
static struct pcep_glob pcep_glob_space = {.dbg = {0, "pathd module: pcep"}};
|
||||
struct pcep_glob *pcep_g = &pcep_glob_space;
|
||||
|
||||
/* Main Thread Even Handler */
|
||||
static int pcep_main_event_handler(enum pcep_main_event_type type, int pcc_id,
|
||||
void *payload);
|
||||
static int pcep_main_event_start_sync(int pcc_id);
|
||||
static int pcep_main_event_start_sync_cb(struct path *path, void *arg);
|
||||
static int pcep_main_event_update_candidate(struct path *path);
|
||||
static int pcep_main_event_remove_candidate_segments(const char *originator,
|
||||
bool force);
|
||||
|
||||
/* Hook Handlers called from the Main Thread */
|
||||
static int pathd_candidate_created_handler(struct srte_candidate *candidate);
|
||||
static int pathd_candidate_updated_handler(struct srte_candidate *candidate);
|
||||
static int pathd_candidate_removed_handler(struct srte_candidate *candidate);
|
||||
|
||||
/* Path manipulation functions */
|
||||
static struct path_metric *pcep_copy_metrics(struct path_metric *metric);
|
||||
static struct path_hop *pcep_copy_hops(struct path_hop *hop);
|
||||
|
||||
/* Module Functions */
|
||||
static int pcep_module_finish(void);
|
||||
static int pcep_module_late_init(struct thread_master *tm);
|
||||
static int pcep_module_init(void);
|
||||
|
||||
/* ------------ Path Helper Functions ------------ */
|
||||
|
||||
struct path *pcep_new_path(void)
|
||||
{
|
||||
struct path *path;
|
||||
path = XCALLOC(MTYPE_PCEP, sizeof(*path));
|
||||
path->binding_sid = MPLS_LABEL_NONE;
|
||||
path->enforce_bandwidth = true;
|
||||
return path;
|
||||
}
|
||||
|
||||
struct path_hop *pcep_new_hop(void)
|
||||
{
|
||||
struct path_hop *hop;
|
||||
hop = XCALLOC(MTYPE_PCEP, sizeof(*hop));
|
||||
return hop;
|
||||
}
|
||||
|
||||
struct path_metric *pcep_new_metric(void)
|
||||
{
|
||||
struct path_metric *metric;
|
||||
metric = XCALLOC(MTYPE_PCEP, sizeof(*metric));
|
||||
return metric;
|
||||
}
|
||||
|
||||
struct path_metric *pcep_copy_metrics(struct path_metric *metric)
|
||||
{
|
||||
if (metric == NULL)
|
||||
return NULL;
|
||||
struct path_metric *new_metric = pcep_new_metric();
|
||||
*new_metric = *metric;
|
||||
new_metric->next = pcep_copy_metrics(metric->next);
|
||||
return new_metric;
|
||||
}
|
||||
|
||||
struct path_hop *pcep_copy_hops(struct path_hop *hop)
|
||||
{
|
||||
if (hop == NULL)
|
||||
return NULL;
|
||||
struct path_hop *new_hop = pcep_new_hop();
|
||||
*new_hop = *hop;
|
||||
new_hop->next = pcep_copy_hops(hop->next);
|
||||
return new_hop;
|
||||
}
|
||||
|
||||
struct path *pcep_copy_path(struct path *path)
|
||||
{
|
||||
struct path *new_path = pcep_new_path();
|
||||
|
||||
*new_path = *path;
|
||||
new_path->first_metric = pcep_copy_metrics(path->first_metric);
|
||||
new_path->first_hop = pcep_copy_hops(path->first_hop);
|
||||
if (path->name != NULL)
|
||||
new_path->name = XSTRDUP(MTYPE_PCEP, path->name);
|
||||
if (path->originator != NULL)
|
||||
new_path->originator = XSTRDUP(MTYPE_PCEP, path->originator);
|
||||
return new_path;
|
||||
}
|
||||
|
||||
void pcep_free_path(struct path *path)
|
||||
{
|
||||
struct path_hop *hop;
|
||||
struct path_metric *metric;
|
||||
char *tmp;
|
||||
|
||||
metric = path->first_metric;
|
||||
while (metric != NULL) {
|
||||
struct path_metric *next = metric->next;
|
||||
XFREE(MTYPE_PCEP, metric);
|
||||
metric = next;
|
||||
}
|
||||
hop = path->first_hop;
|
||||
while (hop != NULL) {
|
||||
struct path_hop *next = hop->next;
|
||||
XFREE(MTYPE_PCEP, hop);
|
||||
hop = next;
|
||||
}
|
||||
if (path->originator != NULL) {
|
||||
/* The path own the memory, it is const so it is clear it
|
||||
shouldn't be modified. XFREE macro do not support type casting
|
||||
so we need a temporary variable */
|
||||
tmp = (char *)path->originator;
|
||||
XFREE(MTYPE_PCEP, tmp);
|
||||
path->originator = NULL;
|
||||
}
|
||||
if (path->name != NULL) {
|
||||
/* The path own the memory, it is const so it is clear it
|
||||
shouldn't be modified. XFREE macro do not support type casting
|
||||
so we need a temporary variable */
|
||||
tmp = (char *)path->name;
|
||||
XFREE(MTYPE_PCEP, tmp);
|
||||
path->name = NULL;
|
||||
}
|
||||
XFREE(MTYPE_PCEP, path);
|
||||
}
|
||||
|
||||
|
||||
/* ------------ Main Thread Even Handler ------------ */
|
||||
|
||||
int pcep_main_event_handler(enum pcep_main_event_type type, int pcc_id,
|
||||
void *payload)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
switch (type) {
|
||||
case PCEP_MAIN_EVENT_START_SYNC:
|
||||
ret = pcep_main_event_start_sync(pcc_id);
|
||||
break;
|
||||
case PCEP_MAIN_EVENT_UPDATE_CANDIDATE:
|
||||
assert(payload != NULL);
|
||||
ret = pcep_main_event_update_candidate((struct path *)payload);
|
||||
break;
|
||||
case PCEP_MAIN_EVENT_REMOVE_CANDIDATE_LSP:
|
||||
ret = pcep_main_event_remove_candidate_segments(
|
||||
(const char *)payload, true);
|
||||
break;
|
||||
default:
|
||||
flog_warn(EC_PATH_PCEP_RECOVERABLE_INTERNAL_ERROR,
|
||||
"Unexpected event received in the main thread: %u",
|
||||
type);
|
||||
break;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int pcep_main_event_start_sync(int pcc_id)
|
||||
{
|
||||
path_pcep_config_list_path(pcep_main_event_start_sync_cb, &pcc_id);
|
||||
pcep_ctrl_sync_done(pcep_g->fpt, pcc_id);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int pcep_main_event_start_sync_cb(struct path *path, void *arg)
|
||||
{
|
||||
int *pcc_id = (int *)arg;
|
||||
pcep_ctrl_sync_path(pcep_g->fpt, *pcc_id, path);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int pcep_main_event_update_candidate(struct path *path)
|
||||
{
|
||||
struct path *resp = NULL;
|
||||
int ret = 0;
|
||||
|
||||
ret = path_pcep_config_update_path(path);
|
||||
if (ret != PATH_NB_ERR && path->srp_id != 0) {
|
||||
/* ODL and Cisco requires the first reported
|
||||
* LSP to have a DOWN status, the later status changes
|
||||
* will be comunicated through hook calls.
|
||||
*/
|
||||
enum pcep_lsp_operational_status real_status;
|
||||
if ((resp = path_pcep_config_get_path(&path->nbkey))) {
|
||||
resp->srp_id = path->srp_id;
|
||||
real_status = resp->status;
|
||||
resp->status = PCEP_LSP_OPERATIONAL_DOWN;
|
||||
pcep_ctrl_send_report(pcep_g->fpt, path->pcc_id, resp);
|
||||
/* If the update did not have any effect and the real
|
||||
* status is not DOWN, we need to send a second report
|
||||
* so the PCE is aware of the real status. This is due
|
||||
* to the fact that NO notification will be received
|
||||
* if the update did not apply any changes */
|
||||
if ((ret == PATH_NB_NO_CHANGE)
|
||||
&& (real_status != PCEP_LSP_OPERATIONAL_DOWN)) {
|
||||
resp->status = real_status;
|
||||
resp->srp_id = 0;
|
||||
pcep_ctrl_send_report(pcep_g->fpt, path->pcc_id,
|
||||
resp);
|
||||
}
|
||||
pcep_free_path(resp);
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
int pcep_main_event_remove_candidate_segments(const char *originator,
|
||||
bool force)
|
||||
{
|
||||
srte_candidate_unset_segment_list(originator, force);
|
||||
/* Avoid compiler warnings about const char* */
|
||||
void *free_ptr = (void *)originator;
|
||||
XFREE(MTYPE_PCEP, free_ptr);
|
||||
|
||||
srte_apply_changes();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* ------------ Hook Handlers Functions Called From Main Thread ------------ */
|
||||
|
||||
int pathd_candidate_created_handler(struct srte_candidate *candidate)
|
||||
{
|
||||
struct path *path = candidate_to_path(candidate);
|
||||
int ret = pcep_ctrl_pathd_event(pcep_g->fpt, PCEP_PATH_CREATED, path);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int pathd_candidate_updated_handler(struct srte_candidate *candidate)
|
||||
{
|
||||
struct path *path = candidate_to_path(candidate);
|
||||
int ret = pcep_ctrl_pathd_event(pcep_g->fpt, PCEP_PATH_UPDATED, path);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int pathd_candidate_removed_handler(struct srte_candidate *candidate)
|
||||
{
|
||||
struct path *path = candidate_to_path(candidate);
|
||||
int ret = pcep_ctrl_pathd_event(pcep_g->fpt, PCEP_PATH_REMOVED, path);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/* ------------ Module Functions ------------ */
|
||||
|
||||
int pcep_module_late_init(struct thread_master *tm)
|
||||
{
|
||||
assert(pcep_g->fpt == NULL);
|
||||
assert(pcep_g->master == NULL);
|
||||
|
||||
struct frr_pthread *fpt;
|
||||
|
||||
if (pcep_ctrl_initialize(tm, &fpt, pcep_main_event_handler))
|
||||
return 1;
|
||||
|
||||
if (pcep_lib_initialize(fpt))
|
||||
return 1;
|
||||
|
||||
pcep_g->master = tm;
|
||||
pcep_g->fpt = fpt;
|
||||
|
||||
hook_register(pathd_candidate_created, pathd_candidate_created_handler);
|
||||
hook_register(pathd_candidate_updated, pathd_candidate_updated_handler);
|
||||
hook_register(pathd_candidate_removed, pathd_candidate_removed_handler);
|
||||
|
||||
hook_register(frr_fini, pcep_module_finish);
|
||||
|
||||
pcep_cli_init();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int pcep_module_finish(void)
|
||||
{
|
||||
pcep_ctrl_finalize(&pcep_g->fpt);
|
||||
pcep_lib_finalize();
|
||||
|
||||
for (int i = 0; i < MAX_PCC; i++)
|
||||
if (pcep_g->pce_opts_cli[i] != NULL)
|
||||
XFREE(MTYPE_PCEP, pcep_g->pce_opts_cli[i]);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int pcep_module_init(void)
|
||||
{
|
||||
pcep_g->num_pce_opts_cli = 0;
|
||||
for (int i = 0; i < MAX_PCE; i++)
|
||||
pcep_g->pce_opts_cli[i] = NULL;
|
||||
pcep_g->num_config_group_opts = 0;
|
||||
for (int i = 0; i < MAX_PCE; i++)
|
||||
pcep_g->config_group_opts[i] = NULL;
|
||||
|
||||
hook_register(frr_late_init, pcep_module_late_init);
|
||||
return 0;
|
||||
}
|
||||
|
||||
FRR_MODULE_SETUP(.name = "frr_pathd_pcep", .version = FRR_VERSION,
|
||||
.description = "FRR pathd PCEP module",
|
||||
.init = pcep_module_init)
|
326
pathd/path_pcep.h
Normal file
326
pathd/path_pcep.h
Normal file
@ -0,0 +1,326 @@
|
||||
/*
|
||||
* Copyright (C) 2020 NetDEF, Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the Free
|
||||
* Software Foundation; either version 2 of the License, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; see the file COPYING; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#ifndef _PATH_PCEP_H_
|
||||
#define _PATH_PCEP_H_
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <debug.h>
|
||||
#include <netinet/tcp.h>
|
||||
#include <pcep_utils_logging.h>
|
||||
#include <pcep_pcc_api.h>
|
||||
#include "mpls.h"
|
||||
#include "pathd/pathd.h"
|
||||
#include "pathd/path_pcep_memory.h"
|
||||
|
||||
#define PCEP_DEFAULT_PORT 4189
|
||||
#define MAX_PCC 32
|
||||
#define MAX_PCE 32
|
||||
#define MAX_TAG_SIZE 50
|
||||
#define PCEP_DEBUG_MODE_BASIC 0x01
|
||||
#define PCEP_DEBUG_MODE_PATH 0x02
|
||||
#define PCEP_DEBUG_MODE_PCEP 0x04
|
||||
#define PCEP_DEBUG_MODE_PCEPLIB 0x08
|
||||
#define PCEP_DEBUG(fmt, ...) \
|
||||
do { \
|
||||
if (DEBUG_FLAGS_CHECK(&pcep_g->dbg, PCEP_DEBUG_MODE_BASIC)) \
|
||||
DEBUGD(&pcep_g->dbg, "pcep: " fmt, ##__VA_ARGS__); \
|
||||
} while (0)
|
||||
#define PCEP_DEBUG_PATH(fmt, ...) \
|
||||
do { \
|
||||
if (DEBUG_FLAGS_CHECK(&pcep_g->dbg, PCEP_DEBUG_MODE_PATH)) \
|
||||
DEBUGD(&pcep_g->dbg, "pcep: " fmt, ##__VA_ARGS__); \
|
||||
} while (0)
|
||||
#define PCEP_DEBUG_PCEP(fmt, ...) \
|
||||
do { \
|
||||
if (DEBUG_FLAGS_CHECK(&pcep_g->dbg, PCEP_DEBUG_MODE_PCEP)) \
|
||||
DEBUGD(&pcep_g->dbg, "pcep: " fmt, ##__VA_ARGS__); \
|
||||
} while (0)
|
||||
#define PCEP_DEBUG_PCEPLIB(priority, fmt, ...) \
|
||||
do { \
|
||||
switch (priority) { \
|
||||
case LOG_DEBUG: \
|
||||
if (DEBUG_FLAGS_CHECK(&pcep_g->dbg, \
|
||||
PCEP_DEBUG_MODE_PCEPLIB)) \
|
||||
DEBUGD(&pcep_g->dbg, "pcep: " fmt, \
|
||||
##__VA_ARGS__); \
|
||||
break; \
|
||||
case LOG_INFO: \
|
||||
if (DEBUG_FLAGS_CHECK(&pcep_g->dbg, \
|
||||
PCEP_DEBUG_MODE_PCEPLIB)) \
|
||||
DEBUGI(&pcep_g->dbg, "pcep: " fmt, \
|
||||
##__VA_ARGS__); \
|
||||
break; \
|
||||
case LOG_NOTICE: \
|
||||
if (DEBUG_FLAGS_CHECK(&pcep_g->dbg, \
|
||||
PCEP_DEBUG_MODE_PCEPLIB)) \
|
||||
DEBUGN(&pcep_g->dbg, "pcep: " fmt, \
|
||||
##__VA_ARGS__); \
|
||||
break; \
|
||||
case LOG_WARNING: \
|
||||
case LOG_ERR: \
|
||||
default: \
|
||||
zlog(priority, "pcep: " fmt, ##__VA_ARGS__); \
|
||||
break; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
struct pcep_config_group_opts {
|
||||
char name[64];
|
||||
char tcp_md5_auth[TCP_MD5SIG_MAXKEYLEN];
|
||||
struct ipaddr source_ip;
|
||||
short source_port;
|
||||
bool draft07;
|
||||
bool pce_initiated;
|
||||
int keep_alive_seconds;
|
||||
int min_keep_alive_seconds;
|
||||
int max_keep_alive_seconds;
|
||||
int dead_timer_seconds;
|
||||
int min_dead_timer_seconds;
|
||||
int max_dead_timer_seconds;
|
||||
int pcep_request_time_seconds;
|
||||
int session_timeout_inteval_seconds;
|
||||
int delegation_timeout_seconds;
|
||||
};
|
||||
|
||||
struct pce_opts {
|
||||
struct ipaddr addr;
|
||||
short port;
|
||||
char pce_name[64];
|
||||
struct pcep_config_group_opts config_opts;
|
||||
uint8_t precedence; /* Multi-PCE precedence */
|
||||
};
|
||||
|
||||
struct pcc_opts {
|
||||
struct ipaddr addr;
|
||||
short port;
|
||||
short msd;
|
||||
};
|
||||
|
||||
/* Encapsulate the pce_opts with needed CLI information */
|
||||
struct pce_opts_cli {
|
||||
struct pce_opts pce_opts;
|
||||
char config_group_name[64];
|
||||
/* These are the values configured in the pcc-peer sub-commands.
|
||||
* These need to be stored for later merging. Notice, it could
|
||||
* be that not all of them are set. */
|
||||
struct pcep_config_group_opts pce_config_group_opts;
|
||||
/* The pce_opts->config_opts will be a merge of the default values,
|
||||
* optional config_group values (which overwrite default values),
|
||||
* and any values configured in the pce sub-commands (which overwrite
|
||||
* both default and config_group values). This flag indicates of the
|
||||
* values need to be merged or not. */
|
||||
bool merged;
|
||||
};
|
||||
|
||||
struct lsp_nb_key {
|
||||
uint32_t color;
|
||||
struct ipaddr endpoint;
|
||||
uint32_t preference;
|
||||
};
|
||||
|
||||
struct sid_mpls {
|
||||
mpls_label_t label;
|
||||
uint8_t traffic_class;
|
||||
bool is_bottom;
|
||||
uint8_t ttl;
|
||||
};
|
||||
|
||||
struct pcep_caps {
|
||||
bool is_stateful;
|
||||
/* If we know the objective functions supported by the PCE.
|
||||
* If we don't know, it doesn't mean the PCE doesn't support any */
|
||||
bool supported_ofs_are_known;
|
||||
/* Defined if we know which objective funtions are supported by the PCE.
|
||||
* One bit per objective function, the bit index being equal to
|
||||
* enum pcep_objfun_type values: bit 0 is not used, bit 1 is
|
||||
* PCEP_OBJFUN_MCP, up to bit 17 that is PCEP_OBJFUN_MSN */
|
||||
uint32_t supported_ofs;
|
||||
};
|
||||
|
||||
union sid {
|
||||
uint32_t value;
|
||||
struct sid_mpls mpls;
|
||||
};
|
||||
|
||||
struct nai {
|
||||
/* NAI type */
|
||||
enum pcep_sr_subobj_nai type;
|
||||
/* Local IP address*/
|
||||
struct ipaddr local_addr;
|
||||
/* Local interface identifier if the NAI is an unnumbered adjacency */
|
||||
uint32_t local_iface;
|
||||
/* Remote address if the NAI is an adjacency */
|
||||
struct ipaddr remote_addr;
|
||||
/* Remote interface identifier if the NAI is an unnumbered adjacency */
|
||||
uint32_t remote_iface;
|
||||
};
|
||||
|
||||
struct path_hop {
|
||||
/* Pointer to the next hop in the path */
|
||||
struct path_hop *next;
|
||||
/* Indicateif this ia a loose or strict hop */
|
||||
bool is_loose;
|
||||
/* Indicate if there is an SID for the hop */
|
||||
bool has_sid;
|
||||
/* Indicate if the hop as a MPLS label */
|
||||
bool is_mpls;
|
||||
/* Indicate if the MPLS label has extra attributes (TTL, class..)*/
|
||||
bool has_attribs;
|
||||
/* Hop's SID if available */
|
||||
union sid sid;
|
||||
/* Indicate if there is a NAI for this hop */
|
||||
bool has_nai;
|
||||
/* NAI if available */
|
||||
struct nai nai;
|
||||
};
|
||||
|
||||
struct path_metric {
|
||||
/* Pointer to the next metric */
|
||||
struct path_metric *next;
|
||||
/* The metric type */
|
||||
enum pcep_metric_types type;
|
||||
/* If the metric should be enforced */
|
||||
bool enforce;
|
||||
/* If the metric value is bound (a maximum) */
|
||||
bool is_bound;
|
||||
/* If the metric value is computed */
|
||||
bool is_computed;
|
||||
/* The metric value */
|
||||
float value;
|
||||
};
|
||||
|
||||
struct path {
|
||||
/* Both the nbkey and the plspid are keys comming from the PCC,
|
||||
but the PCE is only using the plspid. The missing key is looked up by
|
||||
the PCC so we always have both */
|
||||
|
||||
/* The northbound key identifying this path */
|
||||
struct lsp_nb_key nbkey;
|
||||
/* The generated unique PLSP identifier for this path.
|
||||
See draft-ietf-pce-stateful-pce */
|
||||
uint32_t plsp_id;
|
||||
|
||||
/* The transport address the path is comming from, PCE or PCC*/
|
||||
struct ipaddr sender;
|
||||
/* The pcc protocol address, must be the same family as the endpoint */
|
||||
struct ipaddr pcc_addr;
|
||||
|
||||
/* The identifier of the PCC the path is for/from. If 0 it is undefined,
|
||||
meaning it hasn't be set yet or is for all the PCC */
|
||||
int pcc_id;
|
||||
|
||||
/* The origin of the path creation */
|
||||
enum srte_protocol_origin create_origin;
|
||||
/* The origin of the path modification */
|
||||
enum srte_protocol_origin update_origin;
|
||||
/* The identifier of the entity that originated the path */
|
||||
const char *originator;
|
||||
/* The type of the path, for PCE initiated or updated path it is always
|
||||
SRTE_CANDIDATE_TYPE_DYNAMIC */
|
||||
enum srte_candidate_type type;
|
||||
|
||||
/* The following data comes from either the PCC or the PCE if available
|
||||
*/
|
||||
|
||||
/* Path's binding SID */
|
||||
mpls_label_t binding_sid;
|
||||
/* The name of the path */
|
||||
const char *name;
|
||||
/* The request identifier from the PCE, when getting a path from the
|
||||
PCE. See draft-ietf-pce-stateful-pce */
|
||||
uint32_t srp_id;
|
||||
/* The request identifier from the PCC , when getting a path from the
|
||||
PCE after a computation request. See rfc5440, section-7.4 */
|
||||
uint32_t req_id;
|
||||
/* The operational status of the path */
|
||||
enum pcep_lsp_operational_status status;
|
||||
/* If true, the receiver (PCC) must remove the path.
|
||||
See draft-ietf-pce-pce-initiated-lsp */
|
||||
bool do_remove;
|
||||
/* Indicate the given path was removed by the PCC.
|
||||
See draft-ietf-pce-stateful-pce, section-7.3, flag R */
|
||||
bool was_removed;
|
||||
/* Indicate the path is part of the synchronization process.
|
||||
See draft-ietf-pce-stateful-pce, section-7.3, flag S */
|
||||
bool is_synching;
|
||||
/* Indicate if the path bandwidth requirment is defined */
|
||||
bool has_bandwidth;
|
||||
/* Indicate if the bandwidth requirment should be enforced */
|
||||
bool enforce_bandwidth;
|
||||
/* Path required bandwidth if defined */
|
||||
float bandwidth;
|
||||
/* Specify the list of hop defining the path */
|
||||
struct path_hop *first_hop;
|
||||
/* Specify the list of metrics */
|
||||
struct path_metric *first_metric;
|
||||
/* Indicate if the path has a PCC-defined objective function */
|
||||
bool has_pcc_objfun;
|
||||
/* Indicate the PCC-defined objective function is required */
|
||||
bool enforce_pcc_objfun;
|
||||
/* PCC-defined Objective Function */
|
||||
enum objfun_type pcc_objfun;
|
||||
/* Indicate if the path has a PCE-defined objective function */
|
||||
bool has_pce_objfun;
|
||||
/* PCE-defined Objective Function */
|
||||
enum objfun_type pce_objfun;
|
||||
/* Indicate if some affinity filters are defined */
|
||||
bool has_affinity_filters;
|
||||
/* Affinity attribute filters indexed by enum affinity_filter_type - 1
|
||||
*/
|
||||
uint32_t affinity_filters[MAX_AFFINITY_FILTER_TYPE];
|
||||
|
||||
/* The following data need to be specialized for a given PCE */
|
||||
|
||||
/* Indicate the path is delegated to the PCE.
|
||||
See draft-ietf-pce-stateful-pce, section-7.3, flag D */
|
||||
bool is_delegated;
|
||||
/* Indicate if the PCE wants the path to get active.
|
||||
See draft-ietf-pce-stateful-pce, section-7.3, flag A */
|
||||
bool go_active;
|
||||
/* Indicate the given path was created by the PCE,
|
||||
See draft-ietf-pce-pce-initiated-lsp, section-5.3.1, flag C */
|
||||
bool was_created;
|
||||
|
||||
/* The following data is defined for comnputation replies */
|
||||
|
||||
/* Indicate that no path could be computed */
|
||||
bool no_path;
|
||||
};
|
||||
|
||||
struct pcep_glob {
|
||||
struct debug dbg;
|
||||
struct thread_master *master;
|
||||
struct frr_pthread *fpt;
|
||||
uint8_t num_pce_opts_cli;
|
||||
struct pce_opts_cli *pce_opts_cli[MAX_PCE];
|
||||
uint8_t num_config_group_opts;
|
||||
struct pcep_config_group_opts *config_group_opts[MAX_PCE];
|
||||
};
|
||||
|
||||
extern struct pcep_glob *pcep_g;
|
||||
|
||||
/* Path Helper Functions */
|
||||
struct path *pcep_new_path(void);
|
||||
struct path_hop *pcep_new_hop(void);
|
||||
struct path_metric *pcep_new_metric(void);
|
||||
struct path *pcep_copy_path(struct path *path);
|
||||
void pcep_free_path(struct path *path);
|
||||
|
||||
|
||||
#endif // _PATH_PCEP_H_
|
2029
pathd/path_pcep_cli.c
Normal file
2029
pathd/path_pcep_cli.c
Normal file
File diff suppressed because it is too large
Load Diff
27
pathd/path_pcep_cli.h
Normal file
27
pathd/path_pcep_cli.h
Normal file
@ -0,0 +1,27 @@
|
||||
/*
|
||||
* Copyright (C) 2020 Volta Networks, Inc
|
||||
* Brady Johnson
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the Free
|
||||
* Software Foundation; either version 2 of the License, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; see the file COPYING; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#ifndef _PATH_PCEP_CLI_H_
|
||||
#define _PATH_PCEP_CLI_H_
|
||||
|
||||
|
||||
/* PCEP CLI Functions */
|
||||
void pcep_cli_init(void);
|
||||
|
||||
#endif // _PATH_PCEP_CLI_H_
|
435
pathd/path_pcep_config.c
Normal file
435
pathd/path_pcep_config.c
Normal file
@ -0,0 +1,435 @@
|
||||
/*
|
||||
* Copyright (C) 2020 NetDEF, Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the Free
|
||||
* Software Foundation; either version 2 of the License, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; see the file COPYING; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include <northbound.h>
|
||||
#include <yang.h>
|
||||
#include <printfrr.h>
|
||||
#include <pcep-objects.h>
|
||||
#include "pathd/pathd.h"
|
||||
#include "pathd/path_pcep.h"
|
||||
#include "pathd/path_pcep_config.h"
|
||||
#include "pathd/path_pcep_debug.h"
|
||||
#include "thread.h"
|
||||
|
||||
#define MAX_XPATH 256
|
||||
#define MAX_FLOAT_LEN 22
|
||||
#define INETADDR4_MAXLEN 16
|
||||
#define INETADDR6_MAXLEN 40
|
||||
|
||||
|
||||
static void copy_candidate_objfun_info(struct srte_candidate *candidate,
|
||||
struct path *path);
|
||||
static void copy_candidate_affinity_filters(struct srte_candidate *candidate,
|
||||
struct path *path);
|
||||
static struct path_hop *
|
||||
path_pcep_config_list_path_hops(struct srte_segment_list *segment_list);
|
||||
static struct srte_candidate *lookup_candidate(struct lsp_nb_key *key);
|
||||
static char *candidate_name(struct srte_candidate *candidate);
|
||||
static enum pcep_lsp_operational_status
|
||||
status_int_to_ext(enum srte_policy_status status);
|
||||
static enum pcep_sr_subobj_nai pcep_nai_type(enum srte_segment_nai_type type);
|
||||
static enum srte_segment_nai_type srte_nai_type(enum pcep_sr_subobj_nai type);
|
||||
|
||||
static int path_pcep_config_lookup_cb(struct thread *t)
|
||||
{
|
||||
struct path *path = THREAD_ARG(t);
|
||||
struct srte_candidate *candidate = lookup_candidate(&path->nbkey);
|
||||
struct srte_lsp *lsp;
|
||||
|
||||
if (candidate == NULL)
|
||||
return 0;
|
||||
|
||||
lsp = candidate->lsp;
|
||||
|
||||
if (path->name == NULL)
|
||||
path->name = candidate_name(candidate);
|
||||
if (path->type == SRTE_CANDIDATE_TYPE_UNDEFINED)
|
||||
path->type = candidate->type;
|
||||
if (path->create_origin == SRTE_ORIGIN_UNDEFINED)
|
||||
path->create_origin = candidate->protocol_origin;
|
||||
if ((path->update_origin == SRTE_ORIGIN_UNDEFINED)
|
||||
&& (lsp->segment_list != NULL))
|
||||
path->update_origin = lsp->segment_list->protocol_origin;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void path_pcep_config_lookup(struct path *path)
|
||||
{
|
||||
/*
|
||||
* Configuration access is strictly done via the main thread
|
||||
*/
|
||||
thread_execute(master, path_pcep_config_lookup_cb, path, 0);
|
||||
}
|
||||
|
||||
struct path *path_pcep_config_get_path(struct lsp_nb_key *key)
|
||||
{
|
||||
struct srte_candidate *candidate = lookup_candidate(key);
|
||||
if (candidate == NULL)
|
||||
return NULL;
|
||||
return candidate_to_path(candidate);
|
||||
}
|
||||
|
||||
void path_pcep_config_list_path(path_list_cb_t cb, void *arg)
|
||||
{
|
||||
struct path *path;
|
||||
struct srte_policy *policy;
|
||||
struct srte_candidate *candidate;
|
||||
|
||||
RB_FOREACH (policy, srte_policy_head, &srte_policies) {
|
||||
RB_FOREACH (candidate, srte_candidate_head,
|
||||
&policy->candidate_paths) {
|
||||
path = candidate_to_path(candidate);
|
||||
if (!cb(path, arg))
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct path *candidate_to_path(struct srte_candidate *candidate)
|
||||
{
|
||||
char *name;
|
||||
struct path *path;
|
||||
struct path_hop *hop = NULL;
|
||||
struct path_metric *metric = NULL;
|
||||
struct srte_policy *policy;
|
||||
struct srte_lsp *lsp;
|
||||
enum pcep_lsp_operational_status status;
|
||||
enum srte_protocol_origin update_origin = 0;
|
||||
char *originator = NULL;
|
||||
|
||||
policy = candidate->policy;
|
||||
lsp = candidate->lsp;
|
||||
|
||||
if (lsp->segment_list != NULL) {
|
||||
hop = path_pcep_config_list_path_hops(lsp->segment_list);
|
||||
update_origin = lsp->segment_list->protocol_origin;
|
||||
originator = XSTRDUP(MTYPE_PCEP, lsp->segment_list->originator);
|
||||
}
|
||||
path = pcep_new_path();
|
||||
name = candidate_name(candidate);
|
||||
if (CHECK_FLAG(candidate->flags, F_CANDIDATE_BEST)) {
|
||||
status = status_int_to_ext(policy->status);
|
||||
} else {
|
||||
status = PCEP_LSP_OPERATIONAL_DOWN;
|
||||
}
|
||||
for (uint32_t i = 0; i < MAX_METRIC_TYPE; i++) {
|
||||
struct path_metric *path_metric;
|
||||
struct srte_metric *srte_metric = &lsp->metrics[i];
|
||||
if (CHECK_FLAG(srte_metric->flags, F_METRIC_IS_DEFINED)) {
|
||||
path_metric = pcep_new_metric();
|
||||
path_metric->next = metric;
|
||||
metric = path_metric;
|
||||
metric->type = i + 1;
|
||||
metric->value = srte_metric->value;
|
||||
metric->enforce = CHECK_FLAG(srte_metric->flags,
|
||||
F_METRIC_IS_REQUIRED);
|
||||
metric->is_bound = CHECK_FLAG(srte_metric->flags,
|
||||
F_METRIC_IS_BOUND);
|
||||
metric->is_computed = CHECK_FLAG(srte_metric->flags,
|
||||
F_METRIC_IS_COMPUTED);
|
||||
}
|
||||
}
|
||||
*path = (struct path){
|
||||
.nbkey = (struct lsp_nb_key){.color = policy->color,
|
||||
.endpoint = policy->endpoint,
|
||||
.preference =
|
||||
candidate->preference},
|
||||
.create_origin = lsp->protocol_origin,
|
||||
.update_origin = update_origin,
|
||||
.originator = originator,
|
||||
.plsp_id = 0,
|
||||
.name = name,
|
||||
.type = candidate->type,
|
||||
.srp_id = 0,
|
||||
.req_id = 0,
|
||||
.binding_sid = policy->binding_sid,
|
||||
.status = status,
|
||||
.do_remove = false,
|
||||
.go_active = false,
|
||||
.was_created = false,
|
||||
.was_removed = false,
|
||||
.is_synching = false,
|
||||
.is_delegated = false,
|
||||
.first_hop = hop,
|
||||
.first_metric = metric};
|
||||
|
||||
path->has_bandwidth = CHECK_FLAG(lsp->flags, F_CANDIDATE_HAS_BANDWIDTH);
|
||||
if (path->has_bandwidth) {
|
||||
path->enforce_bandwidth =
|
||||
CHECK_FLAG(lsp->flags, F_CANDIDATE_REQUIRED_BANDWIDTH);
|
||||
path->bandwidth = lsp->bandwidth;
|
||||
} else {
|
||||
path->enforce_bandwidth = true;
|
||||
path->bandwidth = 0;
|
||||
}
|
||||
|
||||
copy_candidate_objfun_info(candidate, path);
|
||||
copy_candidate_affinity_filters(candidate, path);
|
||||
|
||||
return path;
|
||||
}
|
||||
|
||||
void copy_candidate_objfun_info(struct srte_candidate *candidate,
|
||||
struct path *path)
|
||||
{
|
||||
struct srte_lsp *lsp = candidate->lsp;
|
||||
|
||||
if (lsp != NULL) {
|
||||
if (CHECK_FLAG(lsp->flags, F_CANDIDATE_HAS_OBJFUN)) {
|
||||
path->has_pce_objfun = true;
|
||||
path->pce_objfun = lsp->objfun;
|
||||
} else {
|
||||
path->has_pce_objfun = false;
|
||||
path->pce_objfun = OBJFUN_UNDEFINED;
|
||||
}
|
||||
}
|
||||
if (CHECK_FLAG(candidate->flags, F_CANDIDATE_HAS_OBJFUN)) {
|
||||
path->has_pcc_objfun = true;
|
||||
path->pcc_objfun = candidate->objfun;
|
||||
path->enforce_pcc_objfun = CHECK_FLAG(
|
||||
candidate->flags, F_CANDIDATE_REQUIRED_OBJFUN);
|
||||
|
||||
} else {
|
||||
path->has_pcc_objfun = false;
|
||||
path->pcc_objfun = OBJFUN_UNDEFINED;
|
||||
UNSET_FLAG(candidate->flags, F_CANDIDATE_REQUIRED_OBJFUN);
|
||||
}
|
||||
}
|
||||
|
||||
void copy_candidate_affinity_filters(struct srte_candidate *candidate,
|
||||
struct path *path)
|
||||
{
|
||||
bool eany = CHECK_FLAG(candidate->flags, F_CANDIDATE_HAS_EXCLUDE_ANY);
|
||||
bool iany = CHECK_FLAG(candidate->flags, F_CANDIDATE_HAS_INCLUDE_ANY);
|
||||
bool iall = CHECK_FLAG(candidate->flags, F_CANDIDATE_HAS_INCLUDE_ALL);
|
||||
path->has_affinity_filters = eany || iany || iall;
|
||||
path->affinity_filters[AFFINITY_FILTER_EXCLUDE_ANY - 1] =
|
||||
eany ? candidate->affinity_filters[AFFINITY_FILTER_EXCLUDE_ANY
|
||||
- 1]
|
||||
: 0;
|
||||
path->affinity_filters[AFFINITY_FILTER_INCLUDE_ANY - 1] =
|
||||
iany ? candidate->affinity_filters[AFFINITY_FILTER_INCLUDE_ANY
|
||||
- 1]
|
||||
: 0;
|
||||
path->affinity_filters[AFFINITY_FILTER_INCLUDE_ALL - 1] =
|
||||
iall ? candidate->affinity_filters[AFFINITY_FILTER_INCLUDE_ALL
|
||||
- 1]
|
||||
: 0;
|
||||
}
|
||||
|
||||
struct path_hop *
|
||||
path_pcep_config_list_path_hops(struct srte_segment_list *segment_list)
|
||||
{
|
||||
struct srte_segment_entry *segment;
|
||||
struct path_hop *hop = NULL, *last_hop = NULL;
|
||||
|
||||
RB_FOREACH_REVERSE (segment, srte_segment_entry_head,
|
||||
&segment_list->segments) {
|
||||
hop = pcep_new_hop();
|
||||
*hop = (struct path_hop){
|
||||
.next = last_hop,
|
||||
.is_loose = false,
|
||||
.has_sid = true,
|
||||
.is_mpls = true,
|
||||
.has_attribs = false,
|
||||
.sid = {.mpls = {.label = segment->sid_value}},
|
||||
.has_nai =
|
||||
segment->nai_type != SRTE_SEGMENT_NAI_TYPE_NONE,
|
||||
.nai = {.type = pcep_nai_type(segment->nai_type)}};
|
||||
switch (segment->nai_type) {
|
||||
case SRTE_SEGMENT_NAI_TYPE_IPV4_NODE:
|
||||
case SRTE_SEGMENT_NAI_TYPE_IPV6_NODE:
|
||||
memcpy(&hop->nai.local_addr, &segment->nai_local_addr,
|
||||
sizeof(struct ipaddr));
|
||||
break;
|
||||
case SRTE_SEGMENT_NAI_TYPE_IPV4_ADJACENCY:
|
||||
case SRTE_SEGMENT_NAI_TYPE_IPV6_ADJACENCY:
|
||||
memcpy(&hop->nai.local_addr, &segment->nai_local_addr,
|
||||
sizeof(struct ipaddr));
|
||||
memcpy(&hop->nai.remote_addr, &segment->nai_remote_addr,
|
||||
sizeof(struct ipaddr));
|
||||
break;
|
||||
case SRTE_SEGMENT_NAI_TYPE_IPV4_UNNUMBERED_ADJACENCY:
|
||||
memcpy(&hop->nai.local_addr, &segment->nai_local_addr,
|
||||
sizeof(struct ipaddr));
|
||||
hop->nai.local_iface = segment->nai_local_iface;
|
||||
memcpy(&hop->nai.remote_addr, &segment->nai_remote_addr,
|
||||
sizeof(struct ipaddr));
|
||||
hop->nai.remote_iface = segment->nai_remote_iface;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
last_hop = hop;
|
||||
}
|
||||
return hop;
|
||||
}
|
||||
|
||||
int path_pcep_config_update_path(struct path *path)
|
||||
{
|
||||
assert(path != NULL);
|
||||
assert(path->nbkey.preference != 0);
|
||||
assert(path->nbkey.endpoint.ipa_type == IPADDR_V4);
|
||||
|
||||
struct path_hop *hop;
|
||||
struct path_metric *metric;
|
||||
int index;
|
||||
char segment_list_name_buff[64 + 1 + 64 + 1 + 11 + 1];
|
||||
char *segment_list_name = NULL;
|
||||
struct srte_candidate *candidate;
|
||||
struct srte_segment_list *segment_list = NULL;
|
||||
struct srte_segment_entry *segment;
|
||||
|
||||
candidate = lookup_candidate(&path->nbkey);
|
||||
|
||||
// if there is no candidate to update we are done
|
||||
if (!candidate)
|
||||
return 0;
|
||||
|
||||
// first clean up old segment list if present
|
||||
if (candidate->lsp->segment_list) {
|
||||
SET_FLAG(candidate->lsp->segment_list->flags,
|
||||
F_SEGMENT_LIST_DELETED);
|
||||
candidate->lsp->segment_list = NULL;
|
||||
}
|
||||
|
||||
if (path->first_hop != NULL) {
|
||||
snprintf(segment_list_name_buff, sizeof(segment_list_name_buff),
|
||||
"%s-%u", path->name, path->plsp_id);
|
||||
segment_list_name = segment_list_name_buff;
|
||||
|
||||
segment_list = srte_segment_list_add(segment_list_name);
|
||||
segment_list->protocol_origin = path->update_origin;
|
||||
strlcpy(segment_list->originator, path->originator,
|
||||
sizeof(segment_list->originator));
|
||||
SET_FLAG(segment_list->flags, F_SEGMENT_LIST_NEW);
|
||||
SET_FLAG(segment_list->flags, F_SEGMENT_LIST_MODIFIED);
|
||||
|
||||
for (hop = path->first_hop, index = 10; hop != NULL;
|
||||
hop = hop->next, index += 10) {
|
||||
assert(hop->has_sid);
|
||||
assert(hop->is_mpls);
|
||||
|
||||
segment = srte_segment_entry_add(segment_list, index);
|
||||
|
||||
segment->sid_value = (mpls_label_t)hop->sid.mpls.label;
|
||||
SET_FLAG(segment->segment_list->flags,
|
||||
F_SEGMENT_LIST_MODIFIED);
|
||||
|
||||
if (hop->has_nai)
|
||||
srte_segment_entry_set_nai(
|
||||
segment, srte_nai_type(hop->nai.type),
|
||||
&hop->nai.local_addr,
|
||||
hop->nai.local_iface,
|
||||
&hop->nai.remote_addr,
|
||||
hop->nai.remote_iface);
|
||||
}
|
||||
}
|
||||
|
||||
candidate->lsp->segment_list = segment_list;
|
||||
SET_FLAG(candidate->flags, F_CANDIDATE_MODIFIED);
|
||||
|
||||
for (metric = path->first_metric; metric != NULL; metric = metric->next)
|
||||
srte_lsp_set_metric(candidate->lsp, metric->type, metric->value,
|
||||
metric->enforce, metric->is_bound,
|
||||
metric->is_computed);
|
||||
|
||||
if (path->has_bandwidth)
|
||||
srte_lsp_set_bandwidth(candidate->lsp, path->bandwidth,
|
||||
path->enforce_bandwidth);
|
||||
|
||||
if (path->has_pce_objfun) {
|
||||
SET_FLAG(candidate->lsp->flags, F_CANDIDATE_HAS_OBJFUN);
|
||||
candidate->lsp->objfun = path->pce_objfun;
|
||||
}
|
||||
|
||||
srte_apply_changes();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct srte_candidate *lookup_candidate(struct lsp_nb_key *key)
|
||||
{
|
||||
struct srte_policy *policy = NULL;
|
||||
policy = srte_policy_find(key->color, &key->endpoint);
|
||||
if (policy == NULL)
|
||||
return NULL;
|
||||
return srte_candidate_find(policy, key->preference);
|
||||
}
|
||||
|
||||
char *candidate_name(struct srte_candidate *candidate)
|
||||
{
|
||||
return asprintfrr(MTYPE_PCEP, "%s-%s", candidate->policy->name,
|
||||
candidate->name);
|
||||
}
|
||||
|
||||
enum pcep_lsp_operational_status
|
||||
status_int_to_ext(enum srte_policy_status status)
|
||||
{
|
||||
switch (status) {
|
||||
case SRTE_POLICY_STATUS_UP:
|
||||
return PCEP_LSP_OPERATIONAL_ACTIVE;
|
||||
case SRTE_POLICY_STATUS_GOING_UP:
|
||||
return PCEP_LSP_OPERATIONAL_GOING_UP;
|
||||
case SRTE_POLICY_STATUS_GOING_DOWN:
|
||||
return PCEP_LSP_OPERATIONAL_GOING_DOWN;
|
||||
default:
|
||||
return PCEP_LSP_OPERATIONAL_DOWN;
|
||||
}
|
||||
}
|
||||
|
||||
enum pcep_sr_subobj_nai pcep_nai_type(enum srte_segment_nai_type type)
|
||||
{
|
||||
switch (type) {
|
||||
case SRTE_SEGMENT_NAI_TYPE_NONE:
|
||||
return PCEP_SR_SUBOBJ_NAI_ABSENT;
|
||||
case SRTE_SEGMENT_NAI_TYPE_IPV4_NODE:
|
||||
return PCEP_SR_SUBOBJ_NAI_IPV4_NODE;
|
||||
case SRTE_SEGMENT_NAI_TYPE_IPV6_NODE:
|
||||
return PCEP_SR_SUBOBJ_NAI_IPV6_NODE;
|
||||
case SRTE_SEGMENT_NAI_TYPE_IPV4_ADJACENCY:
|
||||
return PCEP_SR_SUBOBJ_NAI_IPV4_ADJACENCY;
|
||||
case SRTE_SEGMENT_NAI_TYPE_IPV6_ADJACENCY:
|
||||
return PCEP_SR_SUBOBJ_NAI_IPV6_ADJACENCY;
|
||||
case SRTE_SEGMENT_NAI_TYPE_IPV4_UNNUMBERED_ADJACENCY:
|
||||
return PCEP_SR_SUBOBJ_NAI_UNNUMBERED_IPV4_ADJACENCY;
|
||||
default:
|
||||
return PCEP_SR_SUBOBJ_NAI_UNKNOWN;
|
||||
}
|
||||
}
|
||||
|
||||
enum srte_segment_nai_type srte_nai_type(enum pcep_sr_subobj_nai type)
|
||||
{
|
||||
switch (type) {
|
||||
case PCEP_SR_SUBOBJ_NAI_ABSENT:
|
||||
return SRTE_SEGMENT_NAI_TYPE_NONE;
|
||||
case PCEP_SR_SUBOBJ_NAI_IPV4_NODE:
|
||||
return SRTE_SEGMENT_NAI_TYPE_IPV4_NODE;
|
||||
case PCEP_SR_SUBOBJ_NAI_IPV6_NODE:
|
||||
return SRTE_SEGMENT_NAI_TYPE_IPV6_NODE;
|
||||
case PCEP_SR_SUBOBJ_NAI_IPV4_ADJACENCY:
|
||||
return SRTE_SEGMENT_NAI_TYPE_IPV4_ADJACENCY;
|
||||
case PCEP_SR_SUBOBJ_NAI_IPV6_ADJACENCY:
|
||||
return SRTE_SEGMENT_NAI_TYPE_IPV6_ADJACENCY;
|
||||
case PCEP_SR_SUBOBJ_NAI_UNNUMBERED_IPV4_ADJACENCY:
|
||||
return SRTE_SEGMENT_NAI_TYPE_IPV4_UNNUMBERED_ADJACENCY;
|
||||
default:
|
||||
return SRTE_SEGMENT_NAI_TYPE_NONE;
|
||||
}
|
||||
}
|
44
pathd/path_pcep_config.h
Normal file
44
pathd/path_pcep_config.h
Normal file
@ -0,0 +1,44 @@
|
||||
/*
|
||||
* Copyright (C) 2020 NetDEF, Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the Free
|
||||
* Software Foundation; either version 2 of the License, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; see the file COPYING; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#ifndef _PATH_PCEP_CONFIG_H_
|
||||
#define _PATH_PCEP_CONFIG_H_
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <debug.h>
|
||||
|
||||
#include "pathd/path_pcep.h"
|
||||
|
||||
#define PATH_NB_NO_CHANGE 0
|
||||
#define PATH_NB_OK 1
|
||||
#define PATH_NB_ERR -1
|
||||
|
||||
typedef int (*path_list_cb_t)(struct path *path, void *arg);
|
||||
|
||||
/* Lookup the candidate path and fill up the missing path attributes like name
|
||||
and type. Used for path generated from PCEP message received from the PCE
|
||||
so they contains more information about the candidate path. If no matching
|
||||
policy or candidate path is found, nothing is changed */
|
||||
void path_pcep_config_lookup(struct path *path);
|
||||
struct path *path_pcep_config_get_path(struct lsp_nb_key *key);
|
||||
void path_pcep_config_list_path(path_list_cb_t cb, void *arg);
|
||||
int path_pcep_config_update_path(struct path *path);
|
||||
struct path *candidate_to_path(struct srte_candidate *candidate);
|
||||
|
||||
|
||||
#endif // _PATH_PCEP_CONFIG_H_
|
1077
pathd/path_pcep_controller.c
Normal file
1077
pathd/path_pcep_controller.c
Normal file
File diff suppressed because it is too large
Load Diff
165
pathd/path_pcep_controller.h
Normal file
165
pathd/path_pcep_controller.h
Normal file
@ -0,0 +1,165 @@
|
||||
/*
|
||||
* Copyright (C) 2020 NetDEF, Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the Free
|
||||
* Software Foundation; either version 2 of the License, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; see the file COPYING; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#ifndef _PATH_PCEP_CONTROLLER_H_
|
||||
#define _PATH_PCEP_CONTROLLER_H_
|
||||
|
||||
#include "pathd/path_pcep.h"
|
||||
|
||||
|
||||
enum pcep_main_event_type {
|
||||
PCEP_MAIN_EVENT_UNDEFINED = 0,
|
||||
PCEP_MAIN_EVENT_START_SYNC,
|
||||
PCEP_MAIN_EVENT_UPDATE_CANDIDATE,
|
||||
PCEP_MAIN_EVENT_REMOVE_CANDIDATE_LSP
|
||||
};
|
||||
|
||||
typedef int (*pcep_main_event_handler_t)(enum pcep_main_event_type type,
|
||||
int pcc_id, void *payload);
|
||||
|
||||
enum pcep_pathd_event_type {
|
||||
PCEP_PATH_UNDEFINED = 0,
|
||||
PCEP_PATH_CREATED,
|
||||
PCEP_PATH_UPDATED,
|
||||
PCEP_PATH_REMOVED
|
||||
};
|
||||
|
||||
struct ctrl_state {
|
||||
struct thread_master *main;
|
||||
struct thread_master *self;
|
||||
pcep_main_event_handler_t main_event_handler;
|
||||
struct pcc_opts *pcc_opts;
|
||||
int pcc_count;
|
||||
int pcc_last_id;
|
||||
struct pcc_state *pcc[MAX_PCC];
|
||||
};
|
||||
|
||||
/* Timer handling data structures */
|
||||
|
||||
enum pcep_ctrl_timeout_type { TO_UNDEFINED, TO_COMPUTATION_REQUEST, TO_MAX };
|
||||
|
||||
enum pcep_ctrl_timer_type {
|
||||
TM_UNDEFINED,
|
||||
TM_RECONNECT_PCC,
|
||||
TM_PCEPLIB_TIMER,
|
||||
TM_TIMEOUT,
|
||||
TM_CALCULATE_BEST_PCE,
|
||||
TM_SESSION_TIMEOUT_PCC,
|
||||
TM_MAX
|
||||
};
|
||||
|
||||
struct pcep_ctrl_timer_data {
|
||||
struct ctrl_state *ctrl_state;
|
||||
enum pcep_ctrl_timer_type timer_type;
|
||||
enum pcep_ctrl_timeout_type timeout_type;
|
||||
int pcc_id;
|
||||
void *payload;
|
||||
};
|
||||
|
||||
/* Socket handling data structures */
|
||||
|
||||
enum pcep_ctrl_socket_type { SOCK_PCEPLIB = 1 };
|
||||
|
||||
struct pcep_ctrl_socket_data {
|
||||
struct ctrl_state *ctrl_state;
|
||||
enum pcep_ctrl_socket_type type;
|
||||
bool is_read;
|
||||
int fd;
|
||||
int pcc_id;
|
||||
void *payload;
|
||||
};
|
||||
|
||||
typedef int (*pcep_ctrl_thread_callback)(struct thread *);
|
||||
|
||||
/* PCC connection information, populated in a thread-safe
|
||||
* manner with pcep_ctrl_get_pcc_info() */
|
||||
struct pcep_pcc_info {
|
||||
struct ctrl_state *ctrl_state; /* will be NULL when returned */
|
||||
char pce_name[64];
|
||||
int pcc_id;
|
||||
struct ipaddr pcc_addr;
|
||||
uint16_t pcc_port;
|
||||
int status;
|
||||
short msd;
|
||||
uint32_t next_reqid;
|
||||
uint32_t next_plspid;
|
||||
bool is_best_multi_pce;
|
||||
uint8_t precedence;
|
||||
};
|
||||
|
||||
/* Functions called from the main thread */
|
||||
int pcep_ctrl_initialize(struct thread_master *main_thread,
|
||||
struct frr_pthread **fpt,
|
||||
pcep_main_event_handler_t event_handler);
|
||||
int pcep_ctrl_finalize(struct frr_pthread **fpt);
|
||||
int pcep_ctrl_update_pcc_options(struct frr_pthread *fpt,
|
||||
struct pcc_opts *opts);
|
||||
int pcep_ctrl_update_pce_options(struct frr_pthread *fpt,
|
||||
struct pce_opts *opts);
|
||||
int pcep_ctrl_remove_pcc(struct frr_pthread *fpt, struct pce_opts *pce_opts);
|
||||
int pcep_ctrl_reset_pcc_session(struct frr_pthread *fpt, char *pce_name);
|
||||
int pcep_ctrl_pathd_event(struct frr_pthread *fpt,
|
||||
enum pcep_pathd_event_type type, struct path *path);
|
||||
int pcep_ctrl_sync_path(struct frr_pthread *fpt, int pcc_id, struct path *path);
|
||||
int pcep_ctrl_sync_done(struct frr_pthread *fpt, int pcc_id);
|
||||
struct counters_group *pcep_ctrl_get_counters(struct frr_pthread *fpt,
|
||||
int pcc_id);
|
||||
pcep_session *pcep_ctrl_get_pcep_session(struct frr_pthread *fpt, int pcc_id);
|
||||
struct pcep_pcc_info *pcep_ctrl_get_pcc_info(struct frr_pthread *fpt,
|
||||
const char *pce_name);
|
||||
|
||||
/* Synchronously send a report, the caller is responsible to free the path,
|
||||
* If `pcc_id` is `0` the report is sent by all PCCs */
|
||||
void pcep_ctrl_send_report(struct frr_pthread *fpt, int pcc_id,
|
||||
struct path *path);
|
||||
|
||||
/* Functions called from the controller thread */
|
||||
void pcep_thread_start_sync(struct ctrl_state *ctrl_state, int pcc_id);
|
||||
void pcep_thread_update_path(struct ctrl_state *ctrl_state, int pcc_id,
|
||||
struct path *path);
|
||||
void pcep_thread_cancel_timer(struct thread **thread);
|
||||
void pcep_thread_schedule_reconnect(struct ctrl_state *ctrl_state, int pcc_id,
|
||||
int retry_count, struct thread **thread);
|
||||
void pcep_thread_schedule_timeout(struct ctrl_state *ctrl_state, int pcc_id,
|
||||
enum pcep_ctrl_timeout_type type,
|
||||
uint32_t delay, void *param,
|
||||
struct thread **thread);
|
||||
void pcep_thread_schedule_session_timeout(struct ctrl_state *ctrl_state,
|
||||
int pcc_id, int delay,
|
||||
struct thread **thread);
|
||||
void pcep_thread_remove_candidate_path_segments(struct ctrl_state *ctrl_state,
|
||||
struct pcc_state *pcc_state);
|
||||
|
||||
void pcep_thread_schedule_sync_best_pce(struct ctrl_state *ctrl_state,
|
||||
int pcc_id, int delay,
|
||||
struct thread **thread);
|
||||
void pcep_thread_schedule_pceplib_timer(struct ctrl_state *ctrl_state,
|
||||
int delay, void *payload,
|
||||
struct thread **thread,
|
||||
pcep_ctrl_thread_callback cb);
|
||||
int pcep_thread_socket_read(void *fpt, void **thread, int fd, void *payload,
|
||||
pcep_ctrl_thread_callback cb);
|
||||
int pcep_thread_socket_write(void *fpt, void **thread, int fd, void *payload,
|
||||
pcep_ctrl_thread_callback cb);
|
||||
|
||||
int pcep_thread_send_ctrl_event(void *fpt, void *payload,
|
||||
pcep_ctrl_thread_callback cb);
|
||||
int pcep_thread_pcep_event(struct thread *thread);
|
||||
int pcep_thread_pcc_count(struct ctrl_state *ctrl_state);
|
||||
|
||||
#endif // _PATH_PCEP_CONTROLLER_H_
|
1771
pathd/path_pcep_debug.c
Normal file
1771
pathd/path_pcep_debug.c
Normal file
File diff suppressed because it is too large
Load Diff
56
pathd/path_pcep_debug.h
Normal file
56
pathd/path_pcep_debug.h
Normal file
@ -0,0 +1,56 @@
|
||||
/*
|
||||
* Copyright (C) 2020 NetDEF, Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the Free
|
||||
* Software Foundation; either version 2 of the License, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; see the file COPYING; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#ifndef _PATH_PCEP_DEBUG_H_
|
||||
#define _PATH_PCEP_DEBUG_H_
|
||||
|
||||
#include "pathd/path_debug.h"
|
||||
#include <pcep_pcc_api.h>
|
||||
#include <pcep-objects.h>
|
||||
#include "pathd/path_pcep.h"
|
||||
#include "pathd/path_pcep_controller.h"
|
||||
#include "pathd/path_pcep_pcc.h"
|
||||
#include "pathd/path_pcep_lib.h"
|
||||
|
||||
const char *pcc_status_name(enum pcc_status status);
|
||||
|
||||
const char *pcep_error_type_name(enum pcep_error_type error_type);
|
||||
const char *pcep_error_value_name(enum pcep_error_type error_type,
|
||||
enum pcep_error_value error_value);
|
||||
const char *pcep_event_type_name(pcep_event_type event_type);
|
||||
const char *pcep_message_type_name(enum pcep_message_types pcep_message_type);
|
||||
const char *pcep_object_class_name(enum pcep_object_classes obj_class);
|
||||
const char *pcep_object_type_name(enum pcep_object_classes obj_class,
|
||||
enum pcep_object_types obj_type);
|
||||
const char *pcep_lsp_status_name(enum pcep_lsp_operational_status status);
|
||||
const char *pcep_tlv_type_name(enum pcep_object_tlv_types tlv_type);
|
||||
const char *pcep_ro_type_name(enum pcep_ro_subobj_types ro_type);
|
||||
const char *pcep_nai_type_name(enum pcep_sr_subobj_nai nai_type);
|
||||
const char *pcep_metric_type_name(enum pcep_metric_types type);
|
||||
const char *pcep_nopath_tlv_err_code_name(enum pcep_nopath_tlv_err_codes code);
|
||||
|
||||
const char *format_objfun_set(uint32_t flags);
|
||||
const char *format_pcc_opts(struct pcc_opts *ops);
|
||||
const char *format_pcc_state(struct pcc_state *state);
|
||||
const char *format_ctrl_state(struct ctrl_state *state);
|
||||
const char *format_path(struct path *path);
|
||||
const char *format_pcep_event(pcep_event *event);
|
||||
const char *format_pcep_message(struct pcep_message *msg);
|
||||
const char *format_yang_dnode(struct lyd_node *dnode);
|
||||
|
||||
#endif // _PATH_PCEP_DEBUG_H_
|
1146
pathd/path_pcep_lib.c
Normal file
1146
pathd/path_pcep_lib.c
Normal file
File diff suppressed because it is too large
Load Diff
48
pathd/path_pcep_lib.h
Normal file
48
pathd/path_pcep_lib.h
Normal file
@ -0,0 +1,48 @@
|
||||
/*
|
||||
* Copyright (C) 2020 NetDEF, Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the Free
|
||||
* Software Foundation; either version 2 of the License, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; see the file COPYING; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#ifndef _PATH_PCEP_LIB_H_
|
||||
#define _PATH_PCEP_LIB_H_
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <pcep_pcc_api.h>
|
||||
#include "frr_pthread.h"
|
||||
#include "pathd/path_pcep.h"
|
||||
|
||||
int pcep_lib_initialize(struct frr_pthread *fpt);
|
||||
void pcep_lib_finalize(void);
|
||||
pcep_session *
|
||||
pcep_lib_connect(struct ipaddr *src_addr, int src_port, struct ipaddr *dst_addr,
|
||||
int dst_port, short msd,
|
||||
const struct pcep_config_group_opts *pcep_options);
|
||||
void pcep_lib_disconnect(pcep_session *sess);
|
||||
struct pcep_message *pcep_lib_format_report(struct pcep_caps *caps,
|
||||
struct path *path);
|
||||
struct pcep_message *pcep_lib_format_request(struct pcep_caps *caps,
|
||||
struct path *path);
|
||||
struct pcep_message *pcep_lib_format_request_cancelled(uint32_t reqid);
|
||||
|
||||
struct pcep_message *pcep_lib_format_error(int error_type, int error_value);
|
||||
struct path *pcep_lib_parse_path(struct pcep_message *msg);
|
||||
void pcep_lib_parse_capabilities(struct pcep_message *msg,
|
||||
struct pcep_caps *caps);
|
||||
struct counters_group *pcep_lib_copy_counters(pcep_session *sess);
|
||||
void pcep_lib_free_counters(struct counters_group *counters);
|
||||
pcep_session *pcep_lib_copy_pcep_session(pcep_session *sess);
|
||||
|
||||
#endif // _PATH_PCEP_LIB_H_
|
27
pathd/path_pcep_memory.c
Normal file
27
pathd/path_pcep_memory.c
Normal file
@ -0,0 +1,27 @@
|
||||
/*
|
||||
* Copyright (C) 2020 NetDEF, Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the Free
|
||||
* Software Foundation; either version 2 of the License, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; see the file COPYING; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include <zebra.h>
|
||||
|
||||
#include <memory.h>
|
||||
|
||||
#include "pathd/path_pcep_memory.h"
|
||||
|
||||
DEFINE_MTYPE(PATHD, PCEP, "PCEP module")
|
||||
DEFINE_MTYPE(PATHD, PCEPLIB_INFRA, "PCEPlib Infrastructure")
|
||||
DEFINE_MTYPE(PATHD, PCEPLIB_MESSAGES, "PCEPlib PCEP Messages")
|
28
pathd/path_pcep_memory.h
Normal file
28
pathd/path_pcep_memory.h
Normal file
@ -0,0 +1,28 @@
|
||||
/*
|
||||
* Copyright (C) 2020 NetDEF, Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the Free
|
||||
* Software Foundation; either version 2 of the License, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; see the file COPYING; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#ifndef _FRR_PATH_PCEP_MEMORY_H_
|
||||
#define _FRR_PATH_PCEP_MEMORY_H_
|
||||
|
||||
#include "pathd/path_memory.h"
|
||||
|
||||
DECLARE_MTYPE(PCEP)
|
||||
DECLARE_MTYPE(PCEPLIB_INFRA)
|
||||
DECLARE_MTYPE(PCEPLIB_MESSAGES)
|
||||
|
||||
#endif /* _FRR_PATH_PCEP_MEMORY_H_ */
|
1817
pathd/path_pcep_pcc.c
Normal file
1817
pathd/path_pcep_pcc.c
Normal file
File diff suppressed because it is too large
Load Diff
141
pathd/path_pcep_pcc.h
Normal file
141
pathd/path_pcep_pcc.h
Normal file
@ -0,0 +1,141 @@
|
||||
/*
|
||||
* Copyright (C) 2020 NetDEF, Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the Free
|
||||
* Software Foundation; either version 2 of the License, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; see the file COPYING; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#ifndef _PATH_PCEP_PCC_H_
|
||||
#define _PATH_PCEP_PCC_H_
|
||||
|
||||
#include "typesafe.h"
|
||||
#include "pathd/path_pcep.h"
|
||||
|
||||
enum pcc_status {
|
||||
PCEP_PCC_INITIALIZED = 0,
|
||||
PCEP_PCC_DISCONNECTED,
|
||||
PCEP_PCC_CONNECTING,
|
||||
PCEP_PCC_SYNCHRONIZING,
|
||||
PCEP_PCC_OPERATING
|
||||
};
|
||||
|
||||
PREDECL_HASH(plspid_map)
|
||||
PREDECL_HASH(nbkey_map)
|
||||
PREDECL_HASH(req_map)
|
||||
|
||||
struct plspid_map_data {
|
||||
struct plspid_map_item mi;
|
||||
struct lsp_nb_key nbkey;
|
||||
uint32_t plspid;
|
||||
};
|
||||
|
||||
struct nbkey_map_data {
|
||||
struct nbkey_map_item mi;
|
||||
struct lsp_nb_key nbkey;
|
||||
uint32_t plspid;
|
||||
};
|
||||
|
||||
struct req_map_data {
|
||||
struct req_map_item mi;
|
||||
struct lsp_nb_key nbkey;
|
||||
uint32_t reqid;
|
||||
};
|
||||
|
||||
struct req_entry {
|
||||
RB_ENTRY(req_entry) entry;
|
||||
struct thread *t_retry;
|
||||
int retry_count;
|
||||
bool was_sent;
|
||||
struct path *path;
|
||||
};
|
||||
RB_HEAD(req_entry_head, req_entry);
|
||||
RB_PROTOTYPE(req_entry_head, req_entry, entry, req_entry_compare);
|
||||
|
||||
struct pcc_state {
|
||||
int id;
|
||||
char tag[MAX_TAG_SIZE];
|
||||
enum pcc_status status;
|
||||
uint16_t flags;
|
||||
#define F_PCC_STATE_HAS_IPV4 0x0002
|
||||
#define F_PCC_STATE_HAS_IPV6 0x0004
|
||||
struct pcc_opts *pcc_opts;
|
||||
struct pce_opts *pce_opts;
|
||||
struct in_addr pcc_addr_v4;
|
||||
struct in6_addr pcc_addr_v6;
|
||||
/* PCC transport source address */
|
||||
struct ipaddr pcc_addr_tr;
|
||||
char *originator;
|
||||
pcep_session *sess;
|
||||
uint32_t retry_count;
|
||||
bool synchronized;
|
||||
struct thread *t_reconnect;
|
||||
struct thread *t_update_best;
|
||||
struct thread *t_session_timeout;
|
||||
uint32_t next_reqid;
|
||||
uint32_t next_plspid;
|
||||
struct plspid_map_head plspid_map;
|
||||
struct nbkey_map_head nbkey_map;
|
||||
struct req_map_head req_map;
|
||||
struct req_entry_head requests;
|
||||
struct pcep_caps caps;
|
||||
bool is_best;
|
||||
bool previous_best;
|
||||
};
|
||||
|
||||
struct pcc_state *pcep_pcc_initialize(struct ctrl_state *ctrl_state,
|
||||
int pcc_id);
|
||||
void pcep_pcc_finalize(struct ctrl_state *ctrl_state,
|
||||
struct pcc_state *pcc_state);
|
||||
int pcep_pcc_enable(struct ctrl_state *ctrl_state, struct pcc_state *pcc_state);
|
||||
int pcep_pcc_disable(struct ctrl_state *ctrl_state,
|
||||
struct pcc_state *pcc_state);
|
||||
int pcep_pcc_update(struct ctrl_state *ctrl_state, struct pcc_state *pcc_state,
|
||||
struct pcc_opts *pcc_opts, struct pce_opts *pce_opts);
|
||||
void pcep_pcc_reconnect(struct ctrl_state *ctrl_state,
|
||||
struct pcc_state *pcc_state);
|
||||
void pcep_pcc_pcep_event_handler(struct ctrl_state *ctrl_state,
|
||||
struct pcc_state *pcc_state,
|
||||
pcep_event *event);
|
||||
void pcep_pcc_pathd_event_handler(struct ctrl_state *ctrl_state,
|
||||
struct pcc_state *pcc_state,
|
||||
enum pcep_pathd_event_type type,
|
||||
struct path *path);
|
||||
void pcep_pcc_timeout_handler(struct ctrl_state *ctrl_state,
|
||||
struct pcc_state *pcc_state,
|
||||
enum pcep_ctrl_timer_type type, void *param);
|
||||
void pcep_pcc_sync_path(struct ctrl_state *ctrl_state,
|
||||
struct pcc_state *pcc_state, struct path *path);
|
||||
void pcep_pcc_sync_done(struct ctrl_state *ctrl_state,
|
||||
struct pcc_state *pcc_state);
|
||||
void pcep_pcc_send_report(struct ctrl_state *ctrl_state,
|
||||
struct pcc_state *pcc_state, struct path *path);
|
||||
int pcep_pcc_multi_pce_sync_path(struct ctrl_state *ctrl_state, int pcc_id,
|
||||
struct pcc_state **pcc_state_list);
|
||||
int pcep_pcc_multi_pce_remove_pcc(struct ctrl_state *ctrl_state,
|
||||
struct pcc_state **pcc_state_list);
|
||||
int pcep_pcc_timer_update_best_pce(struct ctrl_state *ctrl_state, int pcc_id);
|
||||
int pcep_pcc_calculate_best_pce(struct pcc_state **pcc);
|
||||
int pcep_pcc_get_pcc_id_by_ip_port(struct pcc_state **pcc,
|
||||
struct pce_opts *pce_opts);
|
||||
int pcep_pcc_get_pcc_id_by_idx(struct pcc_state **pcc, int idx);
|
||||
struct pcc_state *pcep_pcc_get_pcc_by_id(struct pcc_state **pcc, int id);
|
||||
struct pcc_state *pcep_pcc_get_pcc_by_name(struct pcc_state **pcc,
|
||||
const char *pce_name);
|
||||
int pcep_pcc_get_pcc_idx_by_id(struct pcc_state **pcc, int id);
|
||||
int pcep_pcc_get_free_pcc_idx(struct pcc_state **pcc);
|
||||
int pcep_pcc_get_pcc_id(struct pcc_state *pcc);
|
||||
void pcep_pcc_copy_pcc_info(struct pcc_state **pcc,
|
||||
struct pcep_pcc_info *pcc_info);
|
||||
|
||||
#endif // _PATH_PCEP_PCC_H_
|
296
pathd/path_zebra.c
Normal file
296
pathd/path_zebra.c
Normal file
@ -0,0 +1,296 @@
|
||||
/*
|
||||
* Copyright (C) 2020 NetDEF, Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the Free
|
||||
* Software Foundation; either version 2 of the License, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; see the file COPYING; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include "thread.h"
|
||||
#include "log.h"
|
||||
#include "lib_errors.h"
|
||||
#include "if.h"
|
||||
#include "prefix.h"
|
||||
#include "zclient.h"
|
||||
#include "network.h"
|
||||
#include "stream.h"
|
||||
#include "linklist.h"
|
||||
#include "nexthop.h"
|
||||
#include "vrf.h"
|
||||
#include "typesafe.h"
|
||||
|
||||
#include "pathd/pathd.h"
|
||||
#include "pathd/path_zebra.h"
|
||||
|
||||
static struct zclient *zclient;
|
||||
static struct zclient *zclient_sync;
|
||||
|
||||
/* Global Variables */
|
||||
bool g_has_router_id_v4 = false;
|
||||
bool g_has_router_id_v6 = false;
|
||||
struct in_addr g_router_id_v4;
|
||||
struct in6_addr g_router_id_v6;
|
||||
pthread_mutex_t g_router_id_v4_mtx = PTHREAD_MUTEX_INITIALIZER;
|
||||
pthread_mutex_t g_router_id_v6_mtx = PTHREAD_MUTEX_INITIALIZER;
|
||||
|
||||
/**
|
||||
* Gives the IPv4 router ID received from Zebra.
|
||||
*
|
||||
* @param router_id The in_addr strucure where to store the router id
|
||||
* @return true if the router ID was available, false otherwise
|
||||
*/
|
||||
bool get_ipv4_router_id(struct in_addr *router_id)
|
||||
{
|
||||
bool retval = false;
|
||||
assert(router_id != NULL);
|
||||
pthread_mutex_lock(&g_router_id_v4_mtx);
|
||||
if (g_has_router_id_v4) {
|
||||
memcpy(router_id, &g_router_id_v4, sizeof(*router_id));
|
||||
retval = true;
|
||||
}
|
||||
pthread_mutex_unlock(&g_router_id_v4_mtx);
|
||||
return retval;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gives the IPv6 router ID received from Zebra.
|
||||
*
|
||||
* @param router_id The in6_addr strucure where to store the router id
|
||||
* @return true if the router ID was available, false otherwise
|
||||
*/
|
||||
bool get_ipv6_router_id(struct in6_addr *router_id)
|
||||
{
|
||||
bool retval = false;
|
||||
assert(router_id != NULL);
|
||||
pthread_mutex_lock(&g_router_id_v6_mtx);
|
||||
if (g_has_router_id_v6) {
|
||||
memcpy(router_id, &g_router_id_v6, sizeof(*router_id));
|
||||
retval = true;
|
||||
}
|
||||
pthread_mutex_unlock(&g_router_id_v6_mtx);
|
||||
return retval;
|
||||
}
|
||||
|
||||
static void path_zebra_connected(struct zclient *zclient)
|
||||
{
|
||||
struct srte_policy *policy;
|
||||
|
||||
zclient_send_reg_requests(zclient, VRF_DEFAULT);
|
||||
zclient_send_router_id_update(zclient, ZEBRA_ROUTER_ID_ADD, AFI_IP6,
|
||||
VRF_DEFAULT);
|
||||
|
||||
RB_FOREACH (policy, srte_policy_head, &srte_policies) {
|
||||
struct srte_candidate *candidate;
|
||||
struct srte_segment_list *segment_list;
|
||||
|
||||
candidate = policy->best_candidate;
|
||||
if (!candidate)
|
||||
continue;
|
||||
|
||||
segment_list = candidate->lsp->segment_list;
|
||||
if (!segment_list)
|
||||
continue;
|
||||
|
||||
path_zebra_add_sr_policy(policy, segment_list);
|
||||
}
|
||||
}
|
||||
|
||||
static int path_zebra_sr_policy_notify_status(ZAPI_CALLBACK_ARGS)
|
||||
{
|
||||
struct zapi_sr_policy zapi_sr_policy;
|
||||
struct srte_policy *policy;
|
||||
struct srte_candidate *best_candidate_path;
|
||||
|
||||
if (zapi_sr_policy_notify_status_decode(zclient->ibuf, &zapi_sr_policy))
|
||||
return -1;
|
||||
|
||||
policy = srte_policy_find(zapi_sr_policy.color,
|
||||
&zapi_sr_policy.endpoint);
|
||||
if (!policy)
|
||||
return -1;
|
||||
|
||||
best_candidate_path = policy->best_candidate;
|
||||
if (!best_candidate_path)
|
||||
return -1;
|
||||
|
||||
srte_candidate_status_update(best_candidate_path,
|
||||
zapi_sr_policy.status);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Router-id update message from zebra. */
|
||||
static int path_zebra_router_id_update(ZAPI_CALLBACK_ARGS)
|
||||
{
|
||||
struct prefix pref;
|
||||
const char *family;
|
||||
char buf[PREFIX2STR_BUFFER];
|
||||
zebra_router_id_update_read(zclient->ibuf, &pref);
|
||||
if (pref.family == AF_INET) {
|
||||
pthread_mutex_lock(&g_router_id_v4_mtx);
|
||||
memcpy(&g_router_id_v4, &pref.u.prefix4,
|
||||
sizeof(g_router_id_v4));
|
||||
g_has_router_id_v4 = true;
|
||||
inet_ntop(AF_INET, &g_router_id_v4, buf, sizeof(buf));
|
||||
pthread_mutex_unlock(&g_router_id_v4_mtx);
|
||||
family = "IPv4";
|
||||
} else if (pref.family == AF_INET6) {
|
||||
pthread_mutex_lock(&g_router_id_v6_mtx);
|
||||
memcpy(&g_router_id_v6, &pref.u.prefix6,
|
||||
sizeof(g_router_id_v6));
|
||||
g_has_router_id_v6 = true;
|
||||
inet_ntop(AF_INET6, &g_router_id_v6, buf, sizeof(buf));
|
||||
pthread_mutex_unlock(&g_router_id_v6_mtx);
|
||||
family = "IPv6";
|
||||
} else {
|
||||
pthread_mutex_unlock(&g_router_id_v4_mtx);
|
||||
zlog_warn("Unexpected router ID address family for vrf %u: %u",
|
||||
vrf_id, pref.family);
|
||||
return 0;
|
||||
}
|
||||
pthread_mutex_unlock(&g_router_id_v4_mtx);
|
||||
zlog_info("%s Router Id updated for VRF %u: %s", family, vrf_id, buf);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a segment routing policy to Zebra.
|
||||
*
|
||||
* @param policy The policy to add
|
||||
* @param segment_list The segment list for the policy
|
||||
*/
|
||||
void path_zebra_add_sr_policy(struct srte_policy *policy,
|
||||
struct srte_segment_list *segment_list)
|
||||
{
|
||||
struct zapi_sr_policy zp = {};
|
||||
struct srte_segment_entry *segment;
|
||||
|
||||
zp.color = policy->color;
|
||||
zp.endpoint = policy->endpoint;
|
||||
strlcpy(zp.name, policy->name, sizeof(zp.name));
|
||||
zp.segment_list.type = ZEBRA_LSP_SRTE;
|
||||
zp.segment_list.local_label = policy->binding_sid;
|
||||
zp.segment_list.label_num = 0;
|
||||
RB_FOREACH (segment, srte_segment_entry_head, &segment_list->segments)
|
||||
zp.segment_list.labels[zp.segment_list.label_num++] =
|
||||
segment->sid_value;
|
||||
policy->status = SRTE_POLICY_STATUS_GOING_UP;
|
||||
|
||||
(void)zebra_send_sr_policy(zclient, ZEBRA_SR_POLICY_SET, &zp);
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes a segment policy from Zebra.
|
||||
*
|
||||
* @param policy The policy to remove
|
||||
*/
|
||||
void path_zebra_delete_sr_policy(struct srte_policy *policy)
|
||||
{
|
||||
struct zapi_sr_policy zp = {};
|
||||
|
||||
zp.color = policy->color;
|
||||
zp.endpoint = policy->endpoint;
|
||||
strlcpy(zp.name, policy->name, sizeof(zp.name));
|
||||
zp.segment_list.type = ZEBRA_LSP_SRTE;
|
||||
zp.segment_list.local_label = policy->binding_sid;
|
||||
zp.segment_list.label_num = 0;
|
||||
policy->status = SRTE_POLICY_STATUS_DOWN;
|
||||
|
||||
(void)zebra_send_sr_policy(zclient, ZEBRA_SR_POLICY_DELETE, &zp);
|
||||
}
|
||||
|
||||
/**
|
||||
* Allocates a label from Zebra's label manager.
|
||||
*
|
||||
* @param label the label to be allocated
|
||||
* @return 0 if the label has been allocated, -1 otherwise
|
||||
*/
|
||||
int path_zebra_request_label(mpls_label_t label)
|
||||
{
|
||||
int ret;
|
||||
uint32_t start, end;
|
||||
|
||||
ret = lm_get_label_chunk(zclient_sync, 0, label, 1, &start, &end);
|
||||
if (ret < 0) {
|
||||
zlog_warn("%s: error getting label range!", __func__);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Releases a previously allocated label from Zebra's label manager.
|
||||
*
|
||||
* @param label The label to release
|
||||
* @return 0 ifthe label has beel released, -1 otherwise
|
||||
*/
|
||||
void path_zebra_release_label(mpls_label_t label)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = lm_release_label_chunk(zclient_sync, label, label);
|
||||
if (ret < 0)
|
||||
zlog_warn("%s: error releasing label range!", __func__);
|
||||
}
|
||||
|
||||
static void path_zebra_label_manager_connect(void)
|
||||
{
|
||||
/* Connect to label manager. */
|
||||
while (zclient_socket_connect(zclient_sync) < 0) {
|
||||
zlog_warn("%s: error connecting synchronous zclient!",
|
||||
__func__);
|
||||
sleep(1);
|
||||
}
|
||||
set_nonblocking(zclient_sync->sock);
|
||||
|
||||
/* Send hello to notify zebra this is a synchronous client */
|
||||
while (zclient_send_hello(zclient_sync) < 0) {
|
||||
zlog_warn("%s: Error sending hello for synchronous zclient!",
|
||||
__func__);
|
||||
sleep(1);
|
||||
}
|
||||
|
||||
while (lm_label_manager_connect(zclient_sync, 0) != 0) {
|
||||
zlog_warn("%s: error connecting to label manager!", __func__);
|
||||
sleep(1);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes Zebra asynchronous connection.
|
||||
*
|
||||
* @param master The master thread
|
||||
*/
|
||||
void path_zebra_init(struct thread_master *master)
|
||||
{
|
||||
struct zclient_options options = zclient_options_default;
|
||||
options.synchronous = true;
|
||||
|
||||
/* Initialize asynchronous zclient. */
|
||||
zclient = zclient_new(master, &zclient_options_default);
|
||||
zclient_init(zclient, ZEBRA_ROUTE_SRTE, 0, &pathd_privs);
|
||||
zclient->zebra_connected = path_zebra_connected;
|
||||
zclient->sr_policy_notify_status = path_zebra_sr_policy_notify_status;
|
||||
zclient->router_id_update = path_zebra_router_id_update;
|
||||
|
||||
/* Initialize special zclient for synchronous message exchanges. */
|
||||
zclient_sync = zclient_new(master, &options);
|
||||
zclient_sync->sock = -1;
|
||||
zclient_sync->redist_default = ZEBRA_ROUTE_SRTE;
|
||||
zclient_sync->instance = 1;
|
||||
zclient_sync->privs = &pathd_privs;
|
||||
|
||||
/* Connect to the LM. */
|
||||
path_zebra_label_manager_connect();
|
||||
}
|
34
pathd/path_zebra.h
Normal file
34
pathd/path_zebra.h
Normal file
@ -0,0 +1,34 @@
|
||||
/*
|
||||
* Copyright (C) 2020 NetDEF, Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the Free
|
||||
* Software Foundation; either version 2 of the License, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; see the file COPYING; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#ifndef _FRR_PATH_MPLS_H_
|
||||
#define _FRR_PATH_MPLS_H_
|
||||
|
||||
#include <zebra.h>
|
||||
#include "pathd/pathd.h"
|
||||
|
||||
bool get_ipv4_router_id(struct in_addr *router_id);
|
||||
bool get_ipv6_router_id(struct in6_addr *router_id);
|
||||
void path_zebra_add_sr_policy(struct srte_policy *policy,
|
||||
struct srte_segment_list *segment_list);
|
||||
void path_zebra_delete_sr_policy(struct srte_policy *policy);
|
||||
int path_zebra_request_label(mpls_label_t label);
|
||||
void path_zebra_release_label(mpls_label_t label);
|
||||
void path_zebra_init(struct thread_master *master);
|
||||
|
||||
#endif /* _FRR_PATH_MPLS_H_ */
|
1127
pathd/pathd.c
Normal file
1127
pathd/pathd.c
Normal file
File diff suppressed because it is too large
Load Diff
41
pathd/pathd.conf.sample
Normal file
41
pathd/pathd.conf.sample
Normal file
@ -0,0 +1,41 @@
|
||||
! Default pathd configuration sample
|
||||
!
|
||||
password frr
|
||||
log stdout
|
||||
|
||||
segment-routing
|
||||
traffic-eng
|
||||
segment-list test1
|
||||
index 10 mpls label 123
|
||||
index 20 mpls label 456
|
||||
!
|
||||
segment-list test2
|
||||
index 10 mpls label 321
|
||||
index 20 mpls label 654
|
||||
!
|
||||
policy color 1 endpoint 1.1.1.1
|
||||
name one
|
||||
binding-sid 100
|
||||
candidate-path preference 100 name test1 explicit segment-list test1
|
||||
candidate-path preference 200 name test2 explicit segment-list test2
|
||||
!
|
||||
policy color 2 endpoint 2.2.2.2
|
||||
name two
|
||||
binding-sid 101
|
||||
candidate-path preference 100 name def explicit segment-list test2
|
||||
candidate-path preference 200 name dyn dynamic
|
||||
bandwidth 12345
|
||||
metric bound abc 16 required
|
||||
metric te 10
|
||||
!
|
||||
!
|
||||
pcep
|
||||
pcc-peer PCE1
|
||||
address ip 127.0.0.1
|
||||
sr-draft07
|
||||
!
|
||||
pcc
|
||||
peer PCE1
|
||||
!
|
||||
!
|
||||
!
|
412
pathd/pathd.h
Normal file
412
pathd/pathd.h
Normal file
@ -0,0 +1,412 @@
|
||||
/*
|
||||
* Copyright (C) 2020 NetDEF, Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the Free
|
||||
* Software Foundation; either version 2 of the License, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; see the file COPYING; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#ifndef _FRR_PATHD_H_
|
||||
#define _FRR_PATHD_H_
|
||||
|
||||
#include "lib/mpls.h"
|
||||
#include "lib/ipaddr.h"
|
||||
#include "lib/srte.h"
|
||||
#include "lib/hook.h"
|
||||
|
||||
enum srte_protocol_origin {
|
||||
SRTE_ORIGIN_UNDEFINED = 0,
|
||||
SRTE_ORIGIN_PCEP = 1,
|
||||
SRTE_ORIGIN_BGP = 2,
|
||||
SRTE_ORIGIN_LOCAL = 3,
|
||||
};
|
||||
|
||||
enum srte_policy_status {
|
||||
SRTE_POLICY_STATUS_UNKNOWN = 0,
|
||||
SRTE_POLICY_STATUS_DOWN = 1,
|
||||
SRTE_POLICY_STATUS_UP = 2,
|
||||
SRTE_POLICY_STATUS_GOING_DOWN = 3,
|
||||
SRTE_POLICY_STATUS_GOING_UP = 4
|
||||
};
|
||||
|
||||
enum srte_candidate_type {
|
||||
SRTE_CANDIDATE_TYPE_UNDEFINED = 0,
|
||||
SRTE_CANDIDATE_TYPE_EXPLICIT = 1,
|
||||
SRTE_CANDIDATE_TYPE_DYNAMIC = 2,
|
||||
};
|
||||
|
||||
enum srte_candidate_metric_type {
|
||||
/* IGP metric */
|
||||
SRTE_CANDIDATE_METRIC_TYPE_IGP = 1,
|
||||
/* TE metric */
|
||||
SRTE_CANDIDATE_METRIC_TYPE_TE = 2,
|
||||
/* Hop Counts */
|
||||
SRTE_CANDIDATE_METRIC_TYPE_HC = 3,
|
||||
/* Aggregate bandwidth consumption */
|
||||
SRTE_CANDIDATE_METRIC_TYPE_ABC = 4,
|
||||
/* Load of the most loaded link */
|
||||
SRTE_CANDIDATE_METRIC_TYPE_LMLL = 5,
|
||||
/* Cumulative IGP cost */
|
||||
SRTE_CANDIDATE_METRIC_TYPE_CIGP = 6,
|
||||
/* Cumulative TE cost */
|
||||
SRTE_CANDIDATE_METRIC_TYPE_CTE = 7,
|
||||
/* P2MP IGP metric */
|
||||
SRTE_CANDIDATE_METRIC_TYPE_PIGP = 8,
|
||||
/* P2MP TE metric */
|
||||
SRTE_CANDIDATE_METRIC_TYPE_PTE = 9,
|
||||
/* P2MP hop count metric */
|
||||
SRTE_CANDIDATE_METRIC_TYPE_PHC = 10,
|
||||
/* Segment-ID (SID) Depth */
|
||||
SRTE_CANDIDATE_METRIC_TYPE_MSD = 11,
|
||||
/* Path Delay metric */
|
||||
SRTE_CANDIDATE_METRIC_TYPE_PD = 12,
|
||||
/* Path Delay Variation metric */
|
||||
SRTE_CANDIDATE_METRIC_TYPE_PDV = 13,
|
||||
/* Path Loss metric */
|
||||
SRTE_CANDIDATE_METRIC_TYPE_PL = 14,
|
||||
/* P2MP Path Delay metric */
|
||||
SRTE_CANDIDATE_METRIC_TYPE_PPD = 15,
|
||||
/* P2MP Path Delay variation metric */
|
||||
SRTE_CANDIDATE_METRIC_TYPE_PPDV = 16,
|
||||
/* P2MP Path Loss metric */
|
||||
SRTE_CANDIDATE_METRIC_TYPE_PPL = 17,
|
||||
/* Number of adaptations on a path */
|
||||
SRTE_CANDIDATE_METRIC_TYPE_NAP = 18,
|
||||
/* Number of layers on a path */
|
||||
SRTE_CANDIDATE_METRIC_TYPE_NLP = 19,
|
||||
/* Domain Count metric */
|
||||
SRTE_CANDIDATE_METRIC_TYPE_DC = 20,
|
||||
/* Border Node Count metric */
|
||||
SRTE_CANDIDATE_METRIC_TYPE_BNC = 21,
|
||||
};
|
||||
#define MAX_METRIC_TYPE 21
|
||||
|
||||
enum srte_segment_nai_type {
|
||||
SRTE_SEGMENT_NAI_TYPE_NONE = 0,
|
||||
SRTE_SEGMENT_NAI_TYPE_IPV4_NODE = 1,
|
||||
SRTE_SEGMENT_NAI_TYPE_IPV6_NODE = 2,
|
||||
SRTE_SEGMENT_NAI_TYPE_IPV4_ADJACENCY = 3,
|
||||
SRTE_SEGMENT_NAI_TYPE_IPV6_ADJACENCY = 4,
|
||||
SRTE_SEGMENT_NAI_TYPE_IPV4_UNNUMBERED_ADJACENCY = 5
|
||||
};
|
||||
|
||||
enum objfun_type {
|
||||
OBJFUN_UNDEFINED = 0,
|
||||
/* Minimum Cost Path [RFC5541] */
|
||||
OBJFUN_MCP = 1,
|
||||
/* Minimum Load Path [RFC5541] */
|
||||
OBJFUN_MLP = 2,
|
||||
/* Maximum residual Bandwidth Path [RFC5541] */
|
||||
OBJFUN_MBP = 3,
|
||||
/* Minimize aggregate Bandwidth Consumption [RFC5541] */
|
||||
OBJFUN_MBC = 4,
|
||||
/* Minimize the Load of the most loaded Link [RFC5541] */
|
||||
OBJFUN_MLL = 5,
|
||||
/* Minimize the Cumulative Cost of a set of paths [RFC5541] */
|
||||
OBJFUN_MCC = 6,
|
||||
/* Shortest Path Tree [RFC8306] */
|
||||
OBJFUN_SPT = 7,
|
||||
/* Minimum Cost Tree [RFC8306] */
|
||||
OBJFUN_MCT = 8,
|
||||
/* Minimum Packet Loss Path [RFC8233] */
|
||||
OBJFUN_MPLP = 9,
|
||||
/* Maximum Under-Utilized Path [RFC8233] */
|
||||
OBJFUN_MUP = 10,
|
||||
/* Maximum Reserved Under-Utilized Path [RFC8233] */
|
||||
OBJFUN_MRUP = 11,
|
||||
/* Minimize the number of Transit Domains [RFC8685] */
|
||||
OBJFUN_MTD = 12,
|
||||
/* Minimize the number of Border Nodes [RFC8685] */
|
||||
OBJFUN_MBN = 13,
|
||||
/* Minimize the number of Common Transit Domains [RFC8685] */
|
||||
OBJFUN_MCTD = 14,
|
||||
/* Minimize the number of Shared Links [RFC8800] */
|
||||
OBJFUN_MSL = 15,
|
||||
/* Minimize the number of Shared SRLGs [RFC8800] */
|
||||
OBJFUN_MSS = 16,
|
||||
/* Minimize the number of Shared Nodes [RFC8800] */
|
||||
OBJFUN_MSN = 17,
|
||||
};
|
||||
#define MAX_OBJFUN_TYPE 17
|
||||
|
||||
enum affinity_filter_type {
|
||||
AFFINITY_FILTER_UNDEFINED = 0,
|
||||
AFFINITY_FILTER_EXCLUDE_ANY = 1,
|
||||
AFFINITY_FILTER_INCLUDE_ANY = 2,
|
||||
AFFINITY_FILTER_INCLUDE_ALL = 3,
|
||||
};
|
||||
#define MAX_AFFINITY_FILTER_TYPE 3
|
||||
|
||||
struct srte_segment_list;
|
||||
|
||||
struct srte_segment_entry {
|
||||
RB_ENTRY(srte_segment_entry) entry;
|
||||
|
||||
/* The segment list the entry belong to */
|
||||
struct srte_segment_list *segment_list;
|
||||
|
||||
/* Index of the Label. */
|
||||
uint32_t index;
|
||||
|
||||
/* Label Value. */
|
||||
mpls_label_t sid_value;
|
||||
|
||||
/* NAI Type */
|
||||
enum srte_segment_nai_type nai_type;
|
||||
/* NAI local address when nai type is not NONE */
|
||||
struct ipaddr nai_local_addr;
|
||||
/* NAI local interface when nai type is not IPv4 unnumbered adjacency */
|
||||
uint32_t nai_local_iface;
|
||||
/* NAI local interface when nai type is IPv4 or IPv6 adjacency */
|
||||
struct ipaddr nai_remote_addr;
|
||||
/* NAI remote interface when nai type is not IPv4 unnumbered adjacency
|
||||
*/
|
||||
uint32_t nai_remote_iface;
|
||||
};
|
||||
RB_HEAD(srte_segment_entry_head, srte_segment_entry);
|
||||
RB_PROTOTYPE(srte_segment_entry_head, srte_segment_entry, entry,
|
||||
srte_segment_entry_compare)
|
||||
|
||||
struct srte_segment_list {
|
||||
RB_ENTRY(srte_segment_list) entry;
|
||||
|
||||
/* Name of the Segment List. */
|
||||
char name[64];
|
||||
|
||||
/* The Protocol-Origin. */
|
||||
enum srte_protocol_origin protocol_origin;
|
||||
|
||||
/* The Originator */
|
||||
char originator[64];
|
||||
|
||||
/* Nexthops. */
|
||||
struct srte_segment_entry_head segments;
|
||||
|
||||
/* Status flags. */
|
||||
uint16_t flags;
|
||||
#define F_SEGMENT_LIST_NEW 0x0002
|
||||
#define F_SEGMENT_LIST_MODIFIED 0x0004
|
||||
#define F_SEGMENT_LIST_DELETED 0x0008
|
||||
};
|
||||
RB_HEAD(srte_segment_list_head, srte_segment_list);
|
||||
RB_PROTOTYPE(srte_segment_list_head, srte_segment_list, entry,
|
||||
srte_segment_list_compare)
|
||||
|
||||
struct srte_metric {
|
||||
uint16_t flags;
|
||||
#define F_METRIC_IS_DEFINED 0x0001
|
||||
#define F_METRIC_IS_REQUIRED 0x0002
|
||||
#define F_METRIC_IS_BOUND 0x0004
|
||||
#define F_METRIC_IS_COMPUTED 0x0008
|
||||
float value;
|
||||
};
|
||||
|
||||
/* Runtime information about the candidate path */
|
||||
struct srte_lsp {
|
||||
/* Backpointer to the Candidate Path. */
|
||||
struct srte_candidate *candidate;
|
||||
|
||||
/* The associated Segment List. */
|
||||
struct srte_segment_list *segment_list;
|
||||
|
||||
/* The Protocol-Origin. */
|
||||
enum srte_protocol_origin protocol_origin;
|
||||
|
||||
/* The Originator */
|
||||
char originator[64];
|
||||
|
||||
/* The Discriminator */
|
||||
uint32_t discriminator;
|
||||
|
||||
/* Flags. */
|
||||
uint32_t flags;
|
||||
|
||||
/* Metrics LSP Values */
|
||||
struct srte_metric metrics[MAX_METRIC_TYPE];
|
||||
|
||||
/* Bandwidth Configured Value */
|
||||
float bandwidth;
|
||||
|
||||
/* The objective function in used */
|
||||
enum objfun_type objfun;
|
||||
};
|
||||
|
||||
/* Configured candidate path */
|
||||
struct srte_candidate {
|
||||
RB_ENTRY(srte_candidate) entry;
|
||||
|
||||
/* Backpointer to SR Policy */
|
||||
struct srte_policy *policy;
|
||||
|
||||
/* The LSP associated with this candidate path. */
|
||||
struct srte_lsp *lsp;
|
||||
|
||||
/* Administrative preference. */
|
||||
uint32_t preference;
|
||||
|
||||
/* Symbolic Name. */
|
||||
char name[64];
|
||||
|
||||
/* The associated Segment List. */
|
||||
struct srte_segment_list *segment_list;
|
||||
|
||||
/* The Protocol-Origin. */
|
||||
enum srte_protocol_origin protocol_origin;
|
||||
|
||||
/* The Originator */
|
||||
char originator[64];
|
||||
|
||||
/* The Discriminator */
|
||||
uint32_t discriminator;
|
||||
|
||||
/* The Type (explicit or dynamic) */
|
||||
enum srte_candidate_type type;
|
||||
|
||||
/* Flags. */
|
||||
uint32_t flags;
|
||||
#define F_CANDIDATE_BEST 0x0001
|
||||
#define F_CANDIDATE_NEW 0x0002
|
||||
#define F_CANDIDATE_MODIFIED 0x0004
|
||||
#define F_CANDIDATE_DELETED 0x0008
|
||||
#define F_CANDIDATE_HAS_BANDWIDTH 0x0100
|
||||
#define F_CANDIDATE_REQUIRED_BANDWIDTH 0x0200
|
||||
#define F_CANDIDATE_HAS_OBJFUN 0x0400
|
||||
#define F_CANDIDATE_REQUIRED_OBJFUN 0x0800
|
||||
#define F_CANDIDATE_HAS_EXCLUDE_ANY 0x1000
|
||||
#define F_CANDIDATE_HAS_INCLUDE_ANY 0x2000
|
||||
#define F_CANDIDATE_HAS_INCLUDE_ALL 0x4000
|
||||
|
||||
/* Metrics Configured Values */
|
||||
struct srte_metric metrics[MAX_METRIC_TYPE];
|
||||
|
||||
/* Bandwidth Configured Value */
|
||||
float bandwidth;
|
||||
|
||||
/* Configured objective functions */
|
||||
enum objfun_type objfun;
|
||||
|
||||
/* Path constraints attribute filters */
|
||||
uint32_t affinity_filters[MAX_AFFINITY_FILTER_TYPE];
|
||||
|
||||
/* Hooks delaying timer */
|
||||
struct thread *hook_timer;
|
||||
};
|
||||
|
||||
RB_HEAD(srte_candidate_head, srte_candidate);
|
||||
RB_PROTOTYPE(srte_candidate_head, srte_candidate, entry, srte_candidate_compare)
|
||||
|
||||
struct srte_policy {
|
||||
RB_ENTRY(srte_policy) entry;
|
||||
|
||||
/* Color */
|
||||
uint32_t color;
|
||||
|
||||
/* Endpoint */
|
||||
struct ipaddr endpoint;
|
||||
|
||||
/* Name */
|
||||
char name[64];
|
||||
|
||||
/* Binding SID */
|
||||
mpls_label_t binding_sid;
|
||||
|
||||
/* Operational Status of the policy */
|
||||
enum srte_policy_status status;
|
||||
|
||||
/* Best candidate path. */
|
||||
struct srte_candidate *best_candidate;
|
||||
|
||||
/* Candidate Paths */
|
||||
struct srte_candidate_head candidate_paths;
|
||||
/* Status flags. */
|
||||
uint16_t flags;
|
||||
#define F_POLICY_NEW 0x0002
|
||||
#define F_POLICY_MODIFIED 0x0004
|
||||
#define F_POLICY_DELETED 0x0008
|
||||
};
|
||||
RB_HEAD(srte_policy_head, srte_policy);
|
||||
RB_PROTOTYPE(srte_policy_head, srte_policy, entry, srte_policy_compare)
|
||||
|
||||
DECLARE_HOOK(pathd_candidate_created, (struct srte_candidate * candidate),
|
||||
(candidate))
|
||||
DECLARE_HOOK(pathd_candidate_updated, (struct srte_candidate * candidate),
|
||||
(candidate))
|
||||
DECLARE_HOOK(pathd_candidate_removed, (struct srte_candidate * candidate),
|
||||
(candidate))
|
||||
|
||||
extern struct srte_segment_list_head srte_segment_lists;
|
||||
extern struct srte_policy_head srte_policies;
|
||||
extern struct zebra_privs_t pathd_privs;
|
||||
|
||||
/* master thread, defined in path_main.c */
|
||||
extern struct thread_master *master;
|
||||
|
||||
/* pathd.c */
|
||||
struct srte_segment_list *srte_segment_list_add(const char *name);
|
||||
void srte_segment_list_del(struct srte_segment_list *segment_list);
|
||||
struct srte_segment_list *srte_segment_list_find(const char *name);
|
||||
struct srte_segment_entry *
|
||||
srte_segment_entry_add(struct srte_segment_list *segment_list, uint32_t index);
|
||||
void srte_segment_entry_del(struct srte_segment_entry *segment);
|
||||
void srte_segment_entry_set_nai(struct srte_segment_entry *segment,
|
||||
enum srte_segment_nai_type type,
|
||||
struct ipaddr *local_ip, uint32_t local_iface,
|
||||
struct ipaddr *remote_ip,
|
||||
uint32_t remote_iface);
|
||||
struct srte_policy *srte_policy_add(uint32_t color, struct ipaddr *endpoint);
|
||||
void srte_policy_del(struct srte_policy *policy);
|
||||
struct srte_policy *srte_policy_find(uint32_t color, struct ipaddr *endpoint);
|
||||
void srte_policy_update_binding_sid(struct srte_policy *policy,
|
||||
uint32_t binding_sid);
|
||||
void srte_apply_changes(void);
|
||||
void srte_policy_apply_changes(struct srte_policy *policy);
|
||||
struct srte_candidate *srte_candidate_add(struct srte_policy *policy,
|
||||
uint32_t preference);
|
||||
void srte_candidate_del(struct srte_candidate *candidate);
|
||||
void srte_candidate_set_bandwidth(struct srte_candidate *candidate,
|
||||
float bandwidth, bool required);
|
||||
void srte_candidate_unset_bandwidth(struct srte_candidate *candidate);
|
||||
void srte_candidate_set_metric(struct srte_candidate *candidate,
|
||||
enum srte_candidate_metric_type type,
|
||||
float value, bool required, bool is_cound,
|
||||
bool is_computed);
|
||||
void srte_candidate_unset_metric(struct srte_candidate *candidate,
|
||||
enum srte_candidate_metric_type type);
|
||||
void srte_candidate_set_objfun(struct srte_candidate *candidate, bool required,
|
||||
enum objfun_type type);
|
||||
void srte_candidate_unset_objfun(struct srte_candidate *candidate);
|
||||
void srte_candidate_set_affinity_filter(struct srte_candidate *candidate,
|
||||
enum affinity_filter_type type,
|
||||
uint32_t filter);
|
||||
void srte_candidate_unset_affinity_filter(struct srte_candidate *candidate,
|
||||
enum affinity_filter_type type);
|
||||
void srte_lsp_set_bandwidth(struct srte_lsp *lsp, float bandwidth,
|
||||
bool required);
|
||||
void srte_lsp_unset_bandwidth(struct srte_lsp *lsp);
|
||||
void srte_lsp_set_metric(struct srte_lsp *lsp,
|
||||
enum srte_candidate_metric_type type, float value,
|
||||
bool required, bool is_cound, bool is_computed);
|
||||
void srte_lsp_unset_metric(struct srte_lsp *lsp,
|
||||
enum srte_candidate_metric_type type);
|
||||
struct srte_candidate *srte_candidate_find(struct srte_policy *policy,
|
||||
uint32_t preference);
|
||||
struct srte_segment_entry *
|
||||
srte_segment_entry_find(struct srte_segment_list *segment_list, uint32_t index);
|
||||
void srte_candidate_status_update(struct srte_candidate *candidate, int status);
|
||||
void srte_candidate_unset_segment_list(const char *originator, bool force);
|
||||
const char *srte_origin2str(enum srte_protocol_origin origin);
|
||||
|
||||
/* path_cli.c */
|
||||
void path_cli_init(void);
|
||||
|
||||
#endif /* _FRR_PATHD_H_ */
|
79
pathd/subdir.am
Normal file
79
pathd/subdir.am
Normal file
@ -0,0 +1,79 @@
|
||||
#
|
||||
# pathd
|
||||
#
|
||||
|
||||
if PATHD
|
||||
noinst_LIBRARIES += pathd/libpath.a
|
||||
sbin_PROGRAMS += pathd/pathd
|
||||
dist_examples_DATA += pathd/pathd.conf.sample
|
||||
vtysh_scan += $(top_srcdir)/pathd/path_cli.c
|
||||
vtysh_daemons += pathd
|
||||
# TODO add man page
|
||||
#man8 += $(MANBUILD)/pathd.8
|
||||
|
||||
if HAVE_PATHD_PCEP
|
||||
vtysh_scan += $(top_srcdir)/pathd/path_pcep_cli.c
|
||||
module_LTLIBRARIES += pathd/pathd_pcep.la
|
||||
endif
|
||||
|
||||
endif
|
||||
|
||||
pathd_libpath_a_SOURCES = \
|
||||
pathd/path_cli.c \
|
||||
pathd/path_debug.c \
|
||||
pathd/path_errors.c \
|
||||
pathd/path_main.c \
|
||||
pathd/path_memory.c \
|
||||
pathd/path_nb.c \
|
||||
pathd/path_nb_config.c \
|
||||
pathd/path_nb_state.c \
|
||||
pathd/path_zebra.c \
|
||||
pathd/pathd.c \
|
||||
# end
|
||||
|
||||
clippy_scan += \
|
||||
pathd/path_cli.c \
|
||||
# end
|
||||
|
||||
if HAVE_PATHD_PCEP
|
||||
clippy_scan += \
|
||||
pathd/path_pcep_cli.c \
|
||||
# end
|
||||
endif
|
||||
|
||||
noinst_HEADERS += \
|
||||
pathd/path_debug.h \
|
||||
pathd/path_errors.h \
|
||||
pathd/path_memory.h \
|
||||
pathd/path_nb.h \
|
||||
pathd/path_pcep.h \
|
||||
pathd/path_pcep_cli.h \
|
||||
pathd/path_pcep_controller.h \
|
||||
pathd/path_pcep_debug.h \
|
||||
pathd/path_pcep_lib.h \
|
||||
pathd/path_pcep_memory.h \
|
||||
pathd/path_pcep_config.h \
|
||||
pathd/path_pcep_pcc.h \
|
||||
pathd/path_zebra.h \
|
||||
pathd/pathd.h \
|
||||
# end
|
||||
|
||||
pathd_pathd_SOURCES = pathd/path_main.c
|
||||
nodist_pathd_pathd_SOURCES = \
|
||||
yang/frr-pathd.yang.c \
|
||||
# end
|
||||
pathd_pathd_LDADD = pathd/libpath.a lib/libfrr.la -lm $(LIBCAP)
|
||||
|
||||
pathd_pathd_pcep_la_SOURCES = \
|
||||
pathd/path_pcep.c \
|
||||
pathd/path_pcep_cli.c \
|
||||
pathd/path_pcep_controller.c \
|
||||
pathd/path_pcep_debug.c \
|
||||
pathd/path_pcep_lib.c \
|
||||
pathd/path_pcep_memory.c \
|
||||
pathd/path_pcep_config.c \
|
||||
pathd/path_pcep_pcc.c \
|
||||
# end
|
||||
pathd_pathd_pcep_la_CFLAGS = $(WERROR)
|
||||
pathd_pathd_pcep_la_LDFLAGS = -avoid-version -module -shared -export-dynamic
|
||||
pathd_pathd_pcep_la_LIBADD = @PATHD_PCEP_LIBS@
|
@ -27,6 +27,7 @@
|
||||
%{!?with_vrrpd: %global with_vrrpd 1 }
|
||||
%{!?with_rtadv: %global with_rtadv 1 }
|
||||
%{!?with_watchfrr: %global with_watchfrr 1 }
|
||||
%{!?with_pathd: %global with_pathd 1 }
|
||||
|
||||
# user and group
|
||||
%{!?frr_user: %global frr_user frr }
|
||||
@ -87,7 +88,7 @@
|
||||
%{!?frr_gid: %global frr_gid 92 }
|
||||
%{!?vty_gid: %global vty_gid 85 }
|
||||
|
||||
%define daemon_list zebra ripd ospfd bgpd isisd ripngd ospf6d pbrd staticd bfdd fabricd
|
||||
%define daemon_list zebra ripd ospfd bgpd isisd ripngd ospf6d pbrd staticd bfdd fabricd pathd
|
||||
|
||||
%if %{with_ldpd}
|
||||
%define daemon_ldpd ldpd
|
||||
@ -143,7 +144,13 @@
|
||||
%define daemon_bfdd ""
|
||||
%endif
|
||||
|
||||
%define all_daemons %{daemon_list} %{daemon_ldpd} %{daemon_pimd} %{daemon_nhrpd} %{daemon_eigrpd} %{daemon_babeld} %{daemon_watchfrr} %{daemon_pbrd} %{daemon_bfdd} %{daemon_vrrpd}
|
||||
%if %{with_pathd}
|
||||
%define daemon_pathd pathd
|
||||
%else
|
||||
%define daemon_pathd ""
|
||||
%endif
|
||||
|
||||
%define all_daemons %{daemon_list} %{daemon_ldpd} %{daemon_pimd} %{daemon_nhrpd} %{daemon_eigrpd} %{daemon_babeld} %{daemon_watchfrr} %{daemon_pbrd} %{daemon_bfdd} %{daemon_vrrpd} %{daemon_pathd}
|
||||
|
||||
#release sub-revision (the two digits after the CONFDATE)
|
||||
%{!?release_rev: %global release_rev 01 }
|
||||
@ -397,6 +404,11 @@ routing state through standard SNMP MIBs.
|
||||
--enable-bfdd \
|
||||
%else
|
||||
--disable-bfdd \
|
||||
%endif
|
||||
%if %{with_pathd}
|
||||
--enable-pathd \
|
||||
%else
|
||||
--disable-pathd \
|
||||
%endif
|
||||
--enable-snmp
|
||||
# end
|
||||
@ -526,6 +538,9 @@ zebra_spec_add_service fabricd 2618/tcp "Fabricd vty"
|
||||
%if %{with_vrrpd}
|
||||
zebra_spec_add_service vrrpd 2619/tcp "VRRPd vty"
|
||||
%endif
|
||||
%if %{with_pathd}
|
||||
zebra_spec_add_service pathd 2620/tcp "Pathd vty"
|
||||
%endif
|
||||
|
||||
%if "%{initsystem}" == "systemd"
|
||||
for daemon in %all_daemons ; do
|
||||
@ -681,6 +696,9 @@ fi
|
||||
%if %{with_bfdd}
|
||||
%{_sbindir}/bfdd
|
||||
%endif
|
||||
%if %{with_pathd}
|
||||
%{_sbindir}/pathd
|
||||
%endif
|
||||
%{_libdir}/libfrr.so*
|
||||
%{_libdir}/libfrrcares*
|
||||
%{_libdir}/libfrrospf*
|
||||
@ -798,6 +816,9 @@ sed -i 's/ -M rpki//' %{_sysconfdir}/frr/daemons
|
||||
- migrate route-maps to use northbound interface
|
||||
- plus countless bug fixes and other improvements
|
||||
|
||||
* Mon Jun 15 2020 Sascha Kattelmann <sascha@netdef.org>
|
||||
- Add Pathd support
|
||||
|
||||
* Wed May 06 2020 David Lamparter <equinox@opensourcerouting.org> - 7.3.1
|
||||
- upstream 7.3.1
|
||||
|
||||
|
19
tests/topotests/isis-sr-te-topo1/dst/zebra.conf
Normal file
19
tests/topotests/isis-sr-te-topo1/dst/zebra.conf
Normal file
@ -0,0 +1,19 @@
|
||||
log file zebra.log
|
||||
!
|
||||
hostname dst
|
||||
!
|
||||
debug zebra kernel
|
||||
debug zebra packet
|
||||
debug zebra mpls
|
||||
!
|
||||
interface lo
|
||||
ip address 9.9.9.2/32
|
||||
ipv6 address 2001:db8:1066::2/128
|
||||
!
|
||||
interface eth-rt6
|
||||
ip address 10.0.11.2/24
|
||||
!
|
||||
ip forwarding
|
||||
!
|
||||
line vty
|
||||
!
|
16
tests/topotests/isis-sr-te-topo1/rt1/bgpd.conf
Normal file
16
tests/topotests/isis-sr-te-topo1/rt1/bgpd.conf
Normal file
@ -0,0 +1,16 @@
|
||||
log file bgpd.log
|
||||
!
|
||||
router bgp 1
|
||||
bgp router-id 1.1.1.1
|
||||
neighbor 6.6.6.6 remote-as 1
|
||||
neighbor 6.6.6.6 update-source lo
|
||||
!
|
||||
address-family ipv4 unicast
|
||||
redistribute static
|
||||
neighbor 6.6.6.6 next-hop-self
|
||||
neighbor 6.6.6.6 route-map SET_SR_POLICY in
|
||||
exit-address-family
|
||||
!
|
||||
route-map SET_SR_POLICY permit 10
|
||||
set sr-te color 1
|
||||
!
|
30
tests/topotests/isis-sr-te-topo1/rt1/isisd.conf
Normal file
30
tests/topotests/isis-sr-te-topo1/rt1/isisd.conf
Normal file
@ -0,0 +1,30 @@
|
||||
password 1
|
||||
hostname rt1
|
||||
log file isisd.log
|
||||
!
|
||||
debug isis events
|
||||
debug isis route-events
|
||||
debug isis spf-events
|
||||
debug isis sr-events
|
||||
debug isis lsp-gen
|
||||
!
|
||||
interface lo
|
||||
ip router isis 1
|
||||
ipv6 router isis 1
|
||||
isis passive
|
||||
!
|
||||
interface eth-sw1
|
||||
ip router isis 1
|
||||
ipv6 router isis 1
|
||||
isis hello-multiplier 3
|
||||
!
|
||||
router isis 1
|
||||
net 49.0000.0000.0000.0001.00
|
||||
is-type level-1
|
||||
topology ipv6-unicast
|
||||
segment-routing on
|
||||
segment-routing global-block 16000 23999
|
||||
segment-routing node-msd 8
|
||||
segment-routing prefix 1.1.1.1/32 index 10
|
||||
segment-routing prefix 2001:db8:1000::1/128 index 11
|
||||
!
|
21
tests/topotests/isis-sr-te-topo1/rt1/pathd.conf
Normal file
21
tests/topotests/isis-sr-te-topo1/rt1/pathd.conf
Normal file
@ -0,0 +1,21 @@
|
||||
log file pathd.log
|
||||
!
|
||||
hostname rt1
|
||||
!
|
||||
segment-routing
|
||||
traffic-eng
|
||||
segment-list default
|
||||
index 10 mpls label 16050
|
||||
index 20 mpls label 16060
|
||||
!
|
||||
segment-list test
|
||||
index 10 mpls label 16020
|
||||
index 20 mpls label 16040
|
||||
index 30 mpls label 16060
|
||||
!
|
||||
policy color 1 endpoint 6.6.6.6
|
||||
name default
|
||||
binding-sid 1111
|
||||
!
|
||||
!
|
||||
!
|
@ -0,0 +1,91 @@
|
||||
{
|
||||
"1111":{
|
||||
"inLabel":1111,
|
||||
"installed":true,
|
||||
"nexthops":[
|
||||
{
|
||||
"type":"SR-TE",
|
||||
"outLabel":16050,
|
||||
"outLabelStack":[
|
||||
16050,
|
||||
16060
|
||||
],
|
||||
"distance":150,
|
||||
"installed":true,
|
||||
"nexthop":"10.0.1.3"
|
||||
}
|
||||
]
|
||||
},
|
||||
"16020":{
|
||||
"inLabel":16020,
|
||||
"installed":true,
|
||||
"nexthops":[
|
||||
{
|
||||
"type":"SR (IS-IS)",
|
||||
"outLabel":16020,
|
||||
"distance":150,
|
||||
"installed":true,
|
||||
"nexthop":"10.0.1.2"
|
||||
}
|
||||
]
|
||||
},
|
||||
"16030":{
|
||||
"inLabel":16030,
|
||||
"installed":true,
|
||||
"nexthops":[
|
||||
{
|
||||
"type":"SR (IS-IS)",
|
||||
"outLabel":16030,
|
||||
"distance":150,
|
||||
"installed":true,
|
||||
"nexthop":"10.0.1.3"
|
||||
}
|
||||
]
|
||||
},
|
||||
"16040":{
|
||||
"inLabel":16040,
|
||||
"installed":true,
|
||||
"nexthops":[
|
||||
{
|
||||
"type":"SR (IS-IS)",
|
||||
"outLabel":16040,
|
||||
"distance":150,
|
||||
"installed":true,
|
||||
"nexthop":"10.0.1.2"
|
||||
}
|
||||
]
|
||||
},
|
||||
"16050":{
|
||||
"inLabel":16050,
|
||||
"installed":true,
|
||||
"nexthops":[
|
||||
{
|
||||
"type":"SR (IS-IS)",
|
||||
"outLabel":16050,
|
||||
"distance":150,
|
||||
"installed":true,
|
||||
"nexthop":"10.0.1.3"
|
||||
}
|
||||
]
|
||||
},
|
||||
"16060":{
|
||||
"inLabel":16060,
|
||||
"installed":true,
|
||||
"nexthops":[
|
||||
{
|
||||
"type":"SR (IS-IS)",
|
||||
"outLabel":16060,
|
||||
"distance":150,
|
||||
"installed":true,
|
||||
"nexthop":"10.0.1.3"
|
||||
},
|
||||
{
|
||||
"type":"SR (IS-IS)",
|
||||
"outLabel":16060,
|
||||
"distance":150,
|
||||
"installed":true,
|
||||
"nexthop":"10.0.1.2"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
@ -0,0 +1,74 @@
|
||||
{
|
||||
"16020":{
|
||||
"inLabel":16020,
|
||||
"installed":true,
|
||||
"nexthops":[
|
||||
{
|
||||
"type":"SR (IS-IS)",
|
||||
"outLabel":16020,
|
||||
"distance":150,
|
||||
"installed":true,
|
||||
"nexthop":"10.0.1.2"
|
||||
}
|
||||
]
|
||||
},
|
||||
"16030":{
|
||||
"inLabel":16030,
|
||||
"installed":true,
|
||||
"nexthops":[
|
||||
{
|
||||
"type":"SR (IS-IS)",
|
||||
"outLabel":16030,
|
||||
"distance":150,
|
||||
"installed":true,
|
||||
"nexthop":"10.0.1.3"
|
||||
}
|
||||
]
|
||||
},
|
||||
"16040":{
|
||||
"inLabel":16040,
|
||||
"installed":true,
|
||||
"nexthops":[
|
||||
{
|
||||
"type":"SR (IS-IS)",
|
||||
"outLabel":16040,
|
||||
"distance":150,
|
||||
"installed":true,
|
||||
"nexthop":"10.0.1.2"
|
||||
}
|
||||
]
|
||||
},
|
||||
"16050":{
|
||||
"inLabel":16050,
|
||||
"installed":true,
|
||||
"nexthops":[
|
||||
{
|
||||
"type":"SR (IS-IS)",
|
||||
"outLabel":16050,
|
||||
"distance":150,
|
||||
"installed":true,
|
||||
"nexthop":"10.0.1.3"
|
||||
}
|
||||
]
|
||||
},
|
||||
"16060":{
|
||||
"inLabel":16060,
|
||||
"installed":true,
|
||||
"nexthops":[
|
||||
{
|
||||
"type":"SR (IS-IS)",
|
||||
"outLabel":16060,
|
||||
"distance":150,
|
||||
"installed":true,
|
||||
"nexthop":"10.0.1.3"
|
||||
},
|
||||
{
|
||||
"type":"SR (IS-IS)",
|
||||
"outLabel":16060,
|
||||
"distance":150,
|
||||
"installed":true,
|
||||
"nexthop":"10.0.1.2"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
@ -0,0 +1,13 @@
|
||||
{
|
||||
"frr-pathd:pathd": {
|
||||
"srte": {
|
||||
"policy": [
|
||||
{
|
||||
"color": 1,
|
||||
"endpoint": "6.6.6.6",
|
||||
"is-operational": false
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,20 @@
|
||||
{
|
||||
"frr-pathd:pathd": {
|
||||
"srte": {
|
||||
"policy": [
|
||||
{
|
||||
"color": 1,
|
||||
"endpoint": "6.6.6.6",
|
||||
"is-operational": true,
|
||||
"candidate-path": [
|
||||
{
|
||||
"preference": 100,
|
||||
"discriminator": "*",
|
||||
"is-best-candidate-path": true
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,20 @@
|
||||
{
|
||||
"frr-pathd:pathd": {
|
||||
"srte": {
|
||||
"policy": [
|
||||
{
|
||||
"color": 1,
|
||||
"endpoint": "6.6.6.6",
|
||||
"is-operational": true,
|
||||
"candidate-path": [
|
||||
{
|
||||
"preference": 100,
|
||||
"discriminator": "*",
|
||||
"is-best-candidate-path": true
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,25 @@
|
||||
{
|
||||
"frr-pathd:pathd": {
|
||||
"srte": {
|
||||
"policy": [
|
||||
{
|
||||
"color": 1,
|
||||
"endpoint": "6.6.6.6",
|
||||
"is-operational": true,
|
||||
"candidate-path": [
|
||||
{
|
||||
"preference": 100,
|
||||
"discriminator": "*",
|
||||
"is-best-candidate-path": false
|
||||
},
|
||||
{
|
||||
"preference": 200,
|
||||
"discriminator": "*",
|
||||
"is-best-candidate-path": true
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,20 @@
|
||||
{
|
||||
"1111":{
|
||||
"inLabel":1111,
|
||||
"installed":true,
|
||||
"nexthops":[
|
||||
{
|
||||
"type":"SR-TE",
|
||||
"outLabel":16020,
|
||||
"outLabelStack":[
|
||||
16020,
|
||||
16040,
|
||||
16060
|
||||
],
|
||||
"distance":150,
|
||||
"installed":true,
|
||||
"nexthop":"10.0.1.2"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
@ -0,0 +1,21 @@
|
||||
{
|
||||
"1111":{
|
||||
"inLabel":1111,
|
||||
"installed":true,
|
||||
"nexthops":[
|
||||
{
|
||||
"type":"SR-TE",
|
||||
"outLabel":16020,
|
||||
"outLabelStack":[
|
||||
16020,
|
||||
16040,
|
||||
16050,
|
||||
16060
|
||||
],
|
||||
"distance":150,
|
||||
"installed":true,
|
||||
"nexthop":"10.0.1.2"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
@ -0,0 +1,21 @@
|
||||
{
|
||||
"1111":{
|
||||
"inLabel":1111,
|
||||
"installed":true,
|
||||
"nexthops":[
|
||||
{
|
||||
"type":"SR-TE",
|
||||
"outLabel":16020,
|
||||
"outLabelStack":[
|
||||
16020,
|
||||
16040,
|
||||
16030,
|
||||
16060
|
||||
],
|
||||
"distance":150,
|
||||
"installed":true,
|
||||
"nexthop":"10.0.1.2"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
@ -0,0 +1,29 @@
|
||||
{
|
||||
"9.9.9.2\/32":[
|
||||
{
|
||||
"prefix":"9.9.9.2\/32",
|
||||
"protocol":"bgp",
|
||||
"installed":true,
|
||||
"nexthops":[
|
||||
{
|
||||
"ip":"6.6.6.6",
|
||||
"afi":"ipv4",
|
||||
"active":true,
|
||||
"recursive":true,
|
||||
"srteColor":1
|
||||
},
|
||||
{
|
||||
"fib":true,
|
||||
"ip":"10.0.1.3",
|
||||
"afi":"ipv4",
|
||||
"interfaceName":"eth-sw1",
|
||||
"active":true,
|
||||
"labels":[
|
||||
16050,
|
||||
16060
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
@ -0,0 +1,38 @@
|
||||
{
|
||||
"9.9.9.2\/32":[
|
||||
{
|
||||
"prefix":"9.9.9.2\/32",
|
||||
"protocol":"bgp",
|
||||
"installed":true,
|
||||
"nexthops":[
|
||||
{
|
||||
"ip":"6.6.6.6",
|
||||
"afi":"ipv4",
|
||||
"active":true,
|
||||
"recursive":true,
|
||||
"srteColor":1
|
||||
},
|
||||
{
|
||||
"fib":true,
|
||||
"ip":"10.0.1.2",
|
||||
"afi":"ipv4",
|
||||
"interfaceName":"eth-sw1",
|
||||
"active":true,
|
||||
"labels":[
|
||||
16060
|
||||
]
|
||||
},
|
||||
{
|
||||
"fib":true,
|
||||
"ip":"10.0.1.3",
|
||||
"afi":"ipv4",
|
||||
"interfaceName":"eth-sw1",
|
||||
"active":true,
|
||||
"labels":[
|
||||
16060
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
@ -0,0 +1,20 @@
|
||||
{
|
||||
"frr-pathd:pathd": {
|
||||
"srte": {
|
||||
"policy": [
|
||||
{
|
||||
"color": 1,
|
||||
"endpoint": "6.6.6.6",
|
||||
"is-operational": true,
|
||||
"candidate-path": [
|
||||
{
|
||||
"preference": 100,
|
||||
"discriminator": "*",
|
||||
"is-best-candidate-path": true
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,20 @@
|
||||
{
|
||||
"frr-pathd:pathd": {
|
||||
"srte": {
|
||||
"policy": [
|
||||
{
|
||||
"color": 1,
|
||||
"endpoint": "6.6.6.6",
|
||||
"is-operational": false,
|
||||
"candidate-path": [
|
||||
{
|
||||
"preference": 100,
|
||||
"discriminator": "*",
|
||||
"is-best-candidate-path": true
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
19
tests/topotests/isis-sr-te-topo1/rt1/zebra.conf
Normal file
19
tests/topotests/isis-sr-te-topo1/rt1/zebra.conf
Normal file
@ -0,0 +1,19 @@
|
||||
log file zebra.log
|
||||
!
|
||||
hostname rt1
|
||||
!
|
||||
debug zebra kernel
|
||||
debug zebra packet
|
||||
debug zebra mpls
|
||||
!
|
||||
interface lo
|
||||
ip address 1.1.1.1/32
|
||||
ipv6 address 2001:db8:1000::1/128
|
||||
!
|
||||
interface eth-sw1
|
||||
ip address 10.0.1.1/24
|
||||
!
|
||||
ip forwarding
|
||||
!
|
||||
line vty
|
||||
!
|
41
tests/topotests/isis-sr-te-topo1/rt2/isisd.conf
Normal file
41
tests/topotests/isis-sr-te-topo1/rt2/isisd.conf
Normal file
@ -0,0 +1,41 @@
|
||||
hostname rt2
|
||||
log file isisd.log
|
||||
!
|
||||
debug isis events
|
||||
debug isis route-events
|
||||
debug isis spf-events
|
||||
debug isis sr-events
|
||||
debug isis lsp-gen
|
||||
!
|
||||
interface lo
|
||||
ip router isis 1
|
||||
ipv6 router isis 1
|
||||
isis passive
|
||||
!
|
||||
interface eth-sw1
|
||||
ip router isis 1
|
||||
ipv6 router isis 1
|
||||
isis hello-multiplier 3
|
||||
!
|
||||
interface eth-rt4-1
|
||||
ip router isis 1
|
||||
ipv6 router isis 1
|
||||
isis network point-to-point
|
||||
isis hello-multiplier 3
|
||||
!
|
||||
interface eth-rt4-2
|
||||
ip router isis 1
|
||||
ipv6 router isis 1
|
||||
isis network point-to-point
|
||||
isis hello-multiplier 3
|
||||
!
|
||||
router isis 1
|
||||
net 49.0000.0000.0000.0002.00
|
||||
is-type level-1
|
||||
topology ipv6-unicast
|
||||
segment-routing on
|
||||
segment-routing global-block 16000 23999
|
||||
segment-routing node-msd 8
|
||||
segment-routing prefix 2.2.2.2/32 index 20 no-php-flag
|
||||
segment-routing prefix 2001:db8:1000::2/128 index 21 no-php-flag
|
||||
!
|
25
tests/topotests/isis-sr-te-topo1/rt2/zebra.conf
Normal file
25
tests/topotests/isis-sr-te-topo1/rt2/zebra.conf
Normal file
@ -0,0 +1,25 @@
|
||||
log file zebra.log
|
||||
!
|
||||
hostname rt2
|
||||
!
|
||||
debug zebra kernel
|
||||
debug zebra packet
|
||||
debug zebra mpls
|
||||
!
|
||||
interface lo
|
||||
ip address 2.2.2.2/32
|
||||
ipv6 address 2001:db8:1000::2/128
|
||||
!
|
||||
interface eth-sw1
|
||||
ip address 10.0.1.2/24
|
||||
!
|
||||
interface eth-rt4-1
|
||||
ip address 10.0.2.2/24
|
||||
!
|
||||
interface eth-rt4-2
|
||||
ip address 10.0.3.2/24
|
||||
!
|
||||
ip forwarding
|
||||
!
|
||||
line vty
|
||||
!
|
41
tests/topotests/isis-sr-te-topo1/rt3/isisd.conf
Normal file
41
tests/topotests/isis-sr-te-topo1/rt3/isisd.conf
Normal file
@ -0,0 +1,41 @@
|
||||
hostname rt3
|
||||
log file isisd.log
|
||||
!
|
||||
debug isis events
|
||||
debug isis route-events
|
||||
debug isis spf-events
|
||||
debug isis sr-events
|
||||
debug isis lsp-gen
|
||||
!
|
||||
interface lo
|
||||
ip router isis 1
|
||||
ipv6 router isis 1
|
||||
isis passive
|
||||
!
|
||||
interface eth-sw1
|
||||
ip router isis 1
|
||||
ipv6 router isis 1
|
||||
isis hello-multiplier 3
|
||||
!
|
||||
interface eth-rt5-1
|
||||
ip router isis 1
|
||||
ipv6 router isis 1
|
||||
isis network point-to-point
|
||||
isis hello-multiplier 3
|
||||
!
|
||||
interface eth-rt5-2
|
||||
ip router isis 1
|
||||
ipv6 router isis 1
|
||||
isis network point-to-point
|
||||
isis hello-multiplier 3
|
||||
!
|
||||
router isis 1
|
||||
net 49.0000.0000.0000.0003.00
|
||||
is-type level-1
|
||||
topology ipv6-unicast
|
||||
segment-routing on
|
||||
segment-routing global-block 16000 23999
|
||||
segment-routing node-msd 8
|
||||
segment-routing prefix 3.3.3.3/32 index 30 no-php-flag
|
||||
segment-routing prefix 2001:db8:1000::3/128 index 31 no-php-flag
|
||||
!
|
25
tests/topotests/isis-sr-te-topo1/rt3/zebra.conf
Normal file
25
tests/topotests/isis-sr-te-topo1/rt3/zebra.conf
Normal file
@ -0,0 +1,25 @@
|
||||
log file zebra.log
|
||||
!
|
||||
hostname rt3
|
||||
!
|
||||
debug zebra kernel
|
||||
debug zebra packet
|
||||
debug zebra mpls
|
||||
!
|
||||
interface lo
|
||||
ip address 3.3.3.3/32
|
||||
ipv6 address 2001:db8:1000::3/128
|
||||
!
|
||||
interface eth-sw1
|
||||
ip address 10.0.1.3/24
|
||||
!
|
||||
interface eth-rt5-1
|
||||
ip address 10.0.4.3/24
|
||||
!
|
||||
interface eth-rt5-2
|
||||
ip address 10.0.5.3/24
|
||||
!
|
||||
ip forwarding
|
||||
!
|
||||
line vty
|
||||
!
|
48
tests/topotests/isis-sr-te-topo1/rt4/isisd.conf
Normal file
48
tests/topotests/isis-sr-te-topo1/rt4/isisd.conf
Normal file
@ -0,0 +1,48 @@
|
||||
hostname rt4
|
||||
log file isisd.log
|
||||
!
|
||||
debug isis events
|
||||
debug isis route-events
|
||||
debug isis spf-events
|
||||
debug isis sr-events
|
||||
debug isis lsp-gen
|
||||
!
|
||||
interface lo
|
||||
ip router isis 1
|
||||
ipv6 router isis 1
|
||||
isis passive
|
||||
!
|
||||
interface eth-rt2-1
|
||||
ip router isis 1
|
||||
ipv6 router isis 1
|
||||
isis network point-to-point
|
||||
isis hello-multiplier 3
|
||||
!
|
||||
interface eth-rt2-2
|
||||
ip router isis 1
|
||||
ipv6 router isis 1
|
||||
isis network point-to-point
|
||||
isis hello-multiplier 3
|
||||
!
|
||||
interface eth-rt5
|
||||
ip router isis 1
|
||||
ipv6 router isis 1
|
||||
isis network point-to-point
|
||||
isis hello-multiplier 3
|
||||
!
|
||||
interface eth-rt6
|
||||
ip router isis 1
|
||||
ipv6 router isis 1
|
||||
isis network point-to-point
|
||||
isis hello-multiplier 3
|
||||
!
|
||||
router isis 1
|
||||
net 49.0000.0000.0000.0004.00
|
||||
is-type level-1
|
||||
topology ipv6-unicast
|
||||
segment-routing on
|
||||
segment-routing global-block 16000 23999
|
||||
segment-routing node-msd 8
|
||||
segment-routing prefix 4.4.4.4/32 index 40 no-php-flag
|
||||
segment-routing prefix 2001:db8:1000::4/128 index 41 no-php-flag
|
||||
!
|
28
tests/topotests/isis-sr-te-topo1/rt4/zebra.conf
Normal file
28
tests/topotests/isis-sr-te-topo1/rt4/zebra.conf
Normal file
@ -0,0 +1,28 @@
|
||||
log file zebra.log
|
||||
!
|
||||
hostname rt4
|
||||
!
|
||||
debug zebra kernel
|
||||
debug zebra packet
|
||||
debug zebra mpls
|
||||
!
|
||||
interface lo
|
||||
ip address 4.4.4.4/32
|
||||
ipv6 address 2001:db8:1000::4/128
|
||||
!
|
||||
interface eth-rt2-1
|
||||
ip address 10.0.2.4/24
|
||||
!
|
||||
interface eth-rt2-2
|
||||
ip address 10.0.3.4/24
|
||||
!
|
||||
interface eth-rt5
|
||||
ip address 10.0.6.4/24
|
||||
!
|
||||
interface eth-rt6
|
||||
ip address 10.0.7.4/24
|
||||
!
|
||||
ip forwarding
|
||||
!
|
||||
line vty
|
||||
!
|
48
tests/topotests/isis-sr-te-topo1/rt5/isisd.conf
Normal file
48
tests/topotests/isis-sr-te-topo1/rt5/isisd.conf
Normal file
@ -0,0 +1,48 @@
|
||||
hostname rt5
|
||||
log file isisd.log
|
||||
!
|
||||
debug isis events
|
||||
debug isis route-events
|
||||
debug isis spf-events
|
||||
debug isis sr-events
|
||||
debug isis lsp-gen
|
||||
!
|
||||
interface lo
|
||||
ip router isis 1
|
||||
ipv6 router isis 1
|
||||
isis passive
|
||||
!
|
||||
interface eth-rt3-1
|
||||
ip router isis 1
|
||||
ipv6 router isis 1
|
||||
isis network point-to-point
|
||||
isis hello-multiplier 3
|
||||
!
|
||||
interface eth-rt3-2
|
||||
ip router isis 1
|
||||
ipv6 router isis 1
|
||||
isis network point-to-point
|
||||
isis hello-multiplier 3
|
||||
!
|
||||
interface eth-rt4
|
||||
ip router isis 1
|
||||
ipv6 router isis 1
|
||||
isis network point-to-point
|
||||
isis hello-multiplier 3
|
||||
!
|
||||
interface eth-rt6
|
||||
ip router isis 1
|
||||
ipv6 router isis 1
|
||||
isis network point-to-point
|
||||
isis hello-multiplier 3
|
||||
!
|
||||
router isis 1
|
||||
net 49.0000.0000.0000.0005.00
|
||||
is-type level-1
|
||||
topology ipv6-unicast
|
||||
segment-routing on
|
||||
segment-routing global-block 16000 23999
|
||||
segment-routing node-msd 8
|
||||
segment-routing prefix 5.5.5.5/32 index 50 no-php-flag
|
||||
segment-routing prefix 2001:db8:1000::5/128 index 51 no-php-flag
|
||||
!
|
28
tests/topotests/isis-sr-te-topo1/rt5/zebra.conf
Normal file
28
tests/topotests/isis-sr-te-topo1/rt5/zebra.conf
Normal file
@ -0,0 +1,28 @@
|
||||
log file zebra.log
|
||||
!
|
||||
hostname rt5
|
||||
!
|
||||
debug zebra kernel
|
||||
debug zebra packet
|
||||
debug zebra mpls
|
||||
!
|
||||
interface lo
|
||||
ip address 5.5.5.5/32
|
||||
ipv6 address 2001:db8:1000::5/128
|
||||
!
|
||||
interface eth-rt3-1
|
||||
ip address 10.0.4.5/24
|
||||
!
|
||||
interface eth-rt3-2
|
||||
ip address 10.0.5.5/24
|
||||
!
|
||||
interface eth-rt4
|
||||
ip address 10.0.6.5/24
|
||||
!
|
||||
interface eth-rt6
|
||||
ip address 10.0.8.5/24
|
||||
!
|
||||
ip forwarding
|
||||
!
|
||||
line vty
|
||||
!
|
12
tests/topotests/isis-sr-te-topo1/rt6/bgpd.conf
Normal file
12
tests/topotests/isis-sr-te-topo1/rt6/bgpd.conf
Normal file
@ -0,0 +1,12 @@
|
||||
log file bgpd.log
|
||||
!
|
||||
router bgp 1
|
||||
bgp router-id 6.6.6.6
|
||||
neighbor 1.1.1.1 remote-as 1
|
||||
neighbor 1.1.1.1 update-source lo
|
||||
!
|
||||
address-family ipv4 unicast
|
||||
redistribute static
|
||||
neighbor 1.1.1.1 next-hop-self
|
||||
exit-address-family
|
||||
!
|
36
tests/topotests/isis-sr-te-topo1/rt6/isisd.conf
Normal file
36
tests/topotests/isis-sr-te-topo1/rt6/isisd.conf
Normal file
@ -0,0 +1,36 @@
|
||||
hostname rt6
|
||||
log file isisd.log
|
||||
!
|
||||
debug isis events
|
||||
debug isis route-events
|
||||
debug isis spf-events
|
||||
debug isis sr-events
|
||||
debug isis lsp-gen
|
||||
!
|
||||
interface lo
|
||||
ip router isis 1
|
||||
ipv6 router isis 1
|
||||
isis passive
|
||||
!
|
||||
interface eth-rt4
|
||||
ip router isis 1
|
||||
ipv6 router isis 1
|
||||
isis network point-to-point
|
||||
isis hello-multiplier 3
|
||||
!
|
||||
interface eth-rt5
|
||||
ip router isis 1
|
||||
ipv6 router isis 1
|
||||
isis network point-to-point
|
||||
isis hello-multiplier 3
|
||||
!
|
||||
router isis 1
|
||||
net 49.0000.0000.0000.0006.00
|
||||
is-type level-1
|
||||
topology ipv6-unicast
|
||||
segment-routing on
|
||||
segment-routing global-block 16000 23999
|
||||
segment-routing node-msd 8
|
||||
segment-routing prefix 6.6.6.6/32 index 60
|
||||
segment-routing prefix 2001:db8:1000::6/128 index 61
|
||||
!
|
21
tests/topotests/isis-sr-te-topo1/rt6/pathd.conf
Normal file
21
tests/topotests/isis-sr-te-topo1/rt6/pathd.conf
Normal file
@ -0,0 +1,21 @@
|
||||
log file pathd.log
|
||||
!
|
||||
hostname rt6
|
||||
!
|
||||
segment-routing
|
||||
traffic-eng
|
||||
segment-list default
|
||||
index 10 mpls label 16020
|
||||
index 20 mpls label 16010
|
||||
!
|
||||
segment-list test
|
||||
index 10 mpls label 16050
|
||||
index 20 mpls label 16030
|
||||
index 30 mpls label 16010
|
||||
!
|
||||
policy color 1 endpoint 1.1.1.1
|
||||
name default
|
||||
binding-sid 6666
|
||||
!
|
||||
!
|
||||
!
|
@ -0,0 +1,91 @@
|
||||
{
|
||||
"6666":{
|
||||
"inLabel":6666,
|
||||
"installed":true,
|
||||
"nexthops":[
|
||||
{
|
||||
"type":"SR-TE",
|
||||
"outLabel":16020,
|
||||
"outLabelStack":[
|
||||
16020,
|
||||
16010
|
||||
],
|
||||
"distance":150,
|
||||
"installed":true,
|
||||
"nexthop":"10.0.7.4"
|
||||
}
|
||||
]
|
||||
},
|
||||
"16010": {
|
||||
"inLabel": 16010,
|
||||
"installed": true,
|
||||
"nexthops": [
|
||||
{
|
||||
"distance": 150,
|
||||
"installed": true,
|
||||
"nexthop": "10.0.7.4",
|
||||
"outLabel": 16010,
|
||||
"type": "SR (IS-IS)"
|
||||
},
|
||||
{
|
||||
"distance": 150,
|
||||
"installed": true,
|
||||
"nexthop": "10.0.8.5",
|
||||
"outLabel": 16010,
|
||||
"type": "SR (IS-IS)"
|
||||
}
|
||||
]
|
||||
},
|
||||
"16020":{
|
||||
"inLabel":16020,
|
||||
"installed":true,
|
||||
"nexthops":[
|
||||
{
|
||||
"type":"SR (IS-IS)",
|
||||
"outLabel":16020,
|
||||
"distance":150,
|
||||
"installed":true,
|
||||
"nexthop":"10.0.7.4"
|
||||
}
|
||||
]
|
||||
},
|
||||
"16030":{
|
||||
"inLabel":16030,
|
||||
"installed":true,
|
||||
"nexthops":[
|
||||
{
|
||||
"type":"SR (IS-IS)",
|
||||
"outLabel":16030,
|
||||
"distance":150,
|
||||
"installed":true,
|
||||
"nexthop":"10.0.8.5"
|
||||
}
|
||||
]
|
||||
},
|
||||
"16040":{
|
||||
"inLabel":16040,
|
||||
"installed":true,
|
||||
"nexthops":[
|
||||
{
|
||||
"type":"SR (IS-IS)",
|
||||
"outLabel":16040,
|
||||
"distance":150,
|
||||
"installed":true,
|
||||
"nexthop":"10.0.7.4"
|
||||
}
|
||||
]
|
||||
},
|
||||
"16050":{
|
||||
"inLabel":16050,
|
||||
"installed":true,
|
||||
"nexthops":[
|
||||
{
|
||||
"type":"SR (IS-IS)",
|
||||
"outLabel":16050,
|
||||
"distance":150,
|
||||
"installed":true,
|
||||
"nexthop":"10.0.8.5"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
@ -0,0 +1,74 @@
|
||||
{
|
||||
"16010": {
|
||||
"inLabel": 16010,
|
||||
"installed": true,
|
||||
"nexthops": [
|
||||
{
|
||||
"distance": 150,
|
||||
"installed": true,
|
||||
"nexthop": "10.0.7.4",
|
||||
"outLabel": 16010,
|
||||
"type": "SR (IS-IS)"
|
||||
},
|
||||
{
|
||||
"distance": 150,
|
||||
"installed": true,
|
||||
"nexthop": "10.0.8.5",
|
||||
"outLabel": 16010,
|
||||
"type": "SR (IS-IS)"
|
||||
}
|
||||
]
|
||||
},
|
||||
"16020":{
|
||||
"inLabel":16020,
|
||||
"installed":true,
|
||||
"nexthops":[
|
||||
{
|
||||
"type":"SR (IS-IS)",
|
||||
"outLabel":16020,
|
||||
"distance":150,
|
||||
"installed":true,
|
||||
"nexthop":"10.0.7.4"
|
||||
}
|
||||
]
|
||||
},
|
||||
"16030":{
|
||||
"inLabel":16030,
|
||||
"installed":true,
|
||||
"nexthops":[
|
||||
{
|
||||
"type":"SR (IS-IS)",
|
||||
"outLabel":16030,
|
||||
"distance":150,
|
||||
"installed":true,
|
||||
"nexthop":"10.0.8.5"
|
||||
}
|
||||
]
|
||||
},
|
||||
"16040":{
|
||||
"inLabel":16040,
|
||||
"installed":true,
|
||||
"nexthops":[
|
||||
{
|
||||
"type":"SR (IS-IS)",
|
||||
"outLabel":16040,
|
||||
"distance":150,
|
||||
"installed":true,
|
||||
"nexthop":"10.0.7.4"
|
||||
}
|
||||
]
|
||||
},
|
||||
"16050":{
|
||||
"inLabel":16050,
|
||||
"installed":true,
|
||||
"nexthops":[
|
||||
{
|
||||
"type":"SR (IS-IS)",
|
||||
"outLabel":16050,
|
||||
"distance":150,
|
||||
"installed":true,
|
||||
"nexthop":"10.0.8.5"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
@ -0,0 +1,13 @@
|
||||
{
|
||||
"frr-pathd:pathd": {
|
||||
"srte": {
|
||||
"policy": [
|
||||
{
|
||||
"color": 1,
|
||||
"endpoint": "1.1.1.1",
|
||||
"is-operational": false
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,19 @@
|
||||
{
|
||||
"frr-pathd:pathd": {
|
||||
"srte": {
|
||||
"policy": [
|
||||
{
|
||||
"color": 1,
|
||||
"endpoint": "1.1.1.1",
|
||||
"is-operational": true,
|
||||
"candidate-path": [
|
||||
{
|
||||
"preference": 100,
|
||||
"is-best-candidate-path": true
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,19 @@
|
||||
{
|
||||
"frr-pathd:pathd": {
|
||||
"srte": {
|
||||
"policy": [
|
||||
{
|
||||
"color": 1,
|
||||
"endpoint": "1.1.1.1",
|
||||
"is-operational": true,
|
||||
"candidate-path": [
|
||||
{
|
||||
"preference": 100,
|
||||
"is-best-candidate-path": true
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,23 @@
|
||||
{
|
||||
"frr-pathd:pathd": {
|
||||
"srte": {
|
||||
"policy": [
|
||||
{
|
||||
"color": 1,
|
||||
"endpoint": "1.1.1.1",
|
||||
"is-operational": true,
|
||||
"candidate-path": [
|
||||
{
|
||||
"preference": 100,
|
||||
"is-best-candidate-path": false
|
||||
},
|
||||
{
|
||||
"preference": 200,
|
||||
"is-best-candidate-path": true
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,20 @@
|
||||
{
|
||||
"6666":{
|
||||
"inLabel":6666,
|
||||
"installed":true,
|
||||
"nexthops":[
|
||||
{
|
||||
"type":"SR-TE",
|
||||
"outLabel":16050,
|
||||
"outLabelStack":[
|
||||
16050,
|
||||
16030,
|
||||
16010
|
||||
],
|
||||
"distance":150,
|
||||
"installed":true,
|
||||
"nexthop":"10.0.8.5"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
27
tests/topotests/isis-sr-te-topo1/rt6/zebra.conf
Normal file
27
tests/topotests/isis-sr-te-topo1/rt6/zebra.conf
Normal file
@ -0,0 +1,27 @@
|
||||
log file zebra.log
|
||||
!
|
||||
hostname rt6
|
||||
!
|
||||
debug zebra kernel
|
||||
debug zebra packet
|
||||
debug zebra mpls
|
||||
!
|
||||
interface lo
|
||||
ip address 6.6.6.6/32
|
||||
ipv6 address 2001:db8:1000::6/128
|
||||
!
|
||||
interface eth-rt4
|
||||
ip address 10.0.7.6/24
|
||||
!
|
||||
interface eth-rt5
|
||||
ip address 10.0.8.6/24
|
||||
!
|
||||
interface eth-dst
|
||||
ip address 10.0.11.1/24
|
||||
!
|
||||
ip forwarding
|
||||
!
|
||||
ip route 9.9.9.2/32 10.0.11.2
|
||||
!
|
||||
line vty
|
||||
!
|
525
tests/topotests/isis-sr-te-topo1/test_isis_sr_te_topo1.py
Executable file
525
tests/topotests/isis-sr-te-topo1/test_isis_sr_te_topo1.py
Executable file
@ -0,0 +1,525 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
#
|
||||
# test_isis_sr_topo1.py
|
||||
# Part of NetDEF Topology Tests
|
||||
#
|
||||
# Copyright (c) 2019 by
|
||||
# Network Device Education Foundation, Inc. ("NetDEF")
|
||||
#
|
||||
# Permission to use, copy, modify, and/or distribute this software
|
||||
# for any purpose with or without fee is hereby granted, provided
|
||||
# that the above copyright notice and this permission notice appear
|
||||
# in all copies.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS" AND NETDEF DISCLAIMS ALL WARRANTIES
|
||||
# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NETDEF BE LIABLE FOR
|
||||
# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY
|
||||
# DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
|
||||
# WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
|
||||
# ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
|
||||
# OF THIS SOFTWARE.
|
||||
#
|
||||
|
||||
"""
|
||||
test_isis_sr_te_topo1.py:
|
||||
|
||||
+---------+
|
||||
| |
|
||||
| RT1 |
|
||||
| 1.1.1.1 |
|
||||
| |
|
||||
+---------+
|
||||
|eth-sw1
|
||||
|
|
||||
|
|
||||
|
|
||||
+---------+ | +---------+
|
||||
| | | | |
|
||||
| RT2 |eth-sw1 | eth-sw1| RT3 |
|
||||
| 2.2.2.2 +----------+----------+ 3.3.3.3 |
|
||||
| | 10.0.1.0/24 | |
|
||||
+---------+ +---------+
|
||||
eth-rt4-1| |eth-rt4-2 eth-rt5-1| |eth-rt5-2
|
||||
| | | |
|
||||
10.0.2.0/24| |10.0.3.0/24 10.0.4.0/24| |10.0.5.0/24
|
||||
| | | |
|
||||
eth-rt2-1| |eth-rt2-2 eth-rt3-1| |eth-rt3-2
|
||||
+---------+ +---------+
|
||||
| | | |
|
||||
| RT4 | 10.0.6.0/24 | RT5 |
|
||||
| 4.4.4.4 +---------------------+ 5.5.5.5 |
|
||||
| |eth-rt5 eth-rt4| |
|
||||
+---------+ +---------+
|
||||
eth-rt6| |eth-rt6
|
||||
| |
|
||||
10.0.7.0/24| |10.0.8.0/24
|
||||
| +---------+ |
|
||||
| | | |
|
||||
| | RT6 | |
|
||||
+----------+ 6.6.6.6 +-----------+
|
||||
eth-rt4| |eth-rt5
|
||||
+---------+
|
||||
|eth-dst (.1)
|
||||
|
|
||||
|10.0.11.0/24
|
||||
|
|
||||
|eth-rt6 (.2)
|
||||
+---------+
|
||||
| |
|
||||
| DST |
|
||||
| 9.9.9.2 |
|
||||
| |
|
||||
+---------+
|
||||
|
||||
"""
|
||||
|
||||
import os
|
||||
import sys
|
||||
import pytest
|
||||
import json
|
||||
import re
|
||||
from time import sleep
|
||||
from functools import partial
|
||||
|
||||
# Save the Current Working Directory to find configuration files.
|
||||
CWD = os.path.dirname(os.path.realpath(__file__))
|
||||
sys.path.append(os.path.join(CWD, '../'))
|
||||
|
||||
# pylint: disable=C0413
|
||||
# Import topogen and topotest helpers
|
||||
from lib import topotest
|
||||
from lib.topogen import Topogen, TopoRouter, get_topogen
|
||||
from lib.topolog import logger
|
||||
|
||||
# Required to instantiate the topology builder class.
|
||||
from mininet.topo import Topo
|
||||
|
||||
class TemplateTopo(Topo):
|
||||
"Test topology builder"
|
||||
def build(self, *_args, **_opts):
|
||||
"Build function"
|
||||
tgen = get_topogen(self)
|
||||
|
||||
#
|
||||
# Define FRR Routers
|
||||
#
|
||||
for router in ['rt1', 'rt2', 'rt3', 'rt4', 'rt5', 'rt6', 'dst']:
|
||||
tgen.add_router(router)
|
||||
|
||||
#
|
||||
# Define connections
|
||||
#
|
||||
switch = tgen.add_switch('s1')
|
||||
switch.add_link(tgen.gears['rt1'], nodeif="eth-sw1")
|
||||
switch.add_link(tgen.gears['rt2'], nodeif="eth-sw1")
|
||||
switch.add_link(tgen.gears['rt3'], nodeif="eth-sw1")
|
||||
|
||||
switch = tgen.add_switch('s2')
|
||||
switch.add_link(tgen.gears['rt2'], nodeif="eth-rt4-1")
|
||||
switch.add_link(tgen.gears['rt4'], nodeif="eth-rt2-1")
|
||||
|
||||
switch = tgen.add_switch('s3')
|
||||
switch.add_link(tgen.gears['rt2'], nodeif="eth-rt4-2")
|
||||
switch.add_link(tgen.gears['rt4'], nodeif="eth-rt2-2")
|
||||
|
||||
switch = tgen.add_switch('s4')
|
||||
switch.add_link(tgen.gears['rt3'], nodeif="eth-rt5-1")
|
||||
switch.add_link(tgen.gears['rt5'], nodeif="eth-rt3-1")
|
||||
|
||||
switch = tgen.add_switch('s5')
|
||||
switch.add_link(tgen.gears['rt3'], nodeif="eth-rt5-2")
|
||||
switch.add_link(tgen.gears['rt5'], nodeif="eth-rt3-2")
|
||||
|
||||
switch = tgen.add_switch('s6')
|
||||
switch.add_link(tgen.gears['rt4'], nodeif="eth-rt5")
|
||||
switch.add_link(tgen.gears['rt5'], nodeif="eth-rt4")
|
||||
|
||||
switch = tgen.add_switch('s7')
|
||||
switch.add_link(tgen.gears['rt4'], nodeif="eth-rt6")
|
||||
switch.add_link(tgen.gears['rt6'], nodeif="eth-rt4")
|
||||
|
||||
switch = tgen.add_switch('s8')
|
||||
switch.add_link(tgen.gears['rt5'], nodeif="eth-rt6")
|
||||
switch.add_link(tgen.gears['rt6'], nodeif="eth-rt5")
|
||||
|
||||
switch = tgen.add_switch('s9')
|
||||
switch.add_link(tgen.gears['rt6'], nodeif="eth-dst")
|
||||
switch.add_link(tgen.gears['dst'], nodeif="eth-rt6")
|
||||
|
||||
def setup_module(mod):
|
||||
"Sets up the pytest environment"
|
||||
tgen = Topogen(TemplateTopo, mod.__name__)
|
||||
tgen.start_topology()
|
||||
|
||||
router_list = tgen.routers()
|
||||
|
||||
# For all registered routers, load the zebra configuration file
|
||||
for rname, router in router_list.iteritems():
|
||||
router.load_config(
|
||||
TopoRouter.RD_ZEBRA,
|
||||
os.path.join(CWD, '{}/zebra.conf'.format(rname))
|
||||
)
|
||||
router.load_config(
|
||||
TopoRouter.RD_ISIS,
|
||||
os.path.join(CWD, '{}/isisd.conf'.format(rname))
|
||||
)
|
||||
router.load_config(
|
||||
TopoRouter.RD_PATH,
|
||||
os.path.join(CWD, '{}/pathd.conf'.format(rname))
|
||||
)
|
||||
router.load_config(
|
||||
TopoRouter.RD_BGP,
|
||||
os.path.join(CWD, '{}/bgpd.conf'.format(rname))
|
||||
)
|
||||
|
||||
tgen.start_router()
|
||||
|
||||
def teardown_module(mod):
|
||||
"Teardown the pytest environment"
|
||||
tgen = get_topogen()
|
||||
|
||||
# This function tears down the whole topology.
|
||||
tgen.stop_topology()
|
||||
|
||||
def setup_testcase(msg):
|
||||
logger.info(msg)
|
||||
tgen = get_topogen()
|
||||
|
||||
# Skip if previous fatal error condition is raised
|
||||
if tgen.routers_have_failure():
|
||||
pytest.skip(tgen.errors)
|
||||
|
||||
return tgen
|
||||
|
||||
def print_cmd_result(rname, command):
|
||||
print(get_topogen().gears[rname].vtysh_cmd(command, isjson=False))
|
||||
|
||||
def compare_json_test(router, command, reference, exact):
|
||||
output = router.vtysh_cmd(command, isjson=True)
|
||||
result = topotest.json_cmp(output, reference)
|
||||
|
||||
# Note: topotest.json_cmp() just checks on inclusion of keys.
|
||||
# For exact matching also compare the other way around.
|
||||
if not result and exact:
|
||||
return topotest.json_cmp(reference, output)
|
||||
else:
|
||||
return result
|
||||
|
||||
def cmp_json_output(rname, command, reference, exact=False):
|
||||
"Compare router JSON output"
|
||||
|
||||
logger.info('Comparing router "%s" "%s" output', rname, command)
|
||||
|
||||
tgen = get_topogen()
|
||||
filename = '{}/{}/{}'.format(CWD, rname, reference)
|
||||
expected = json.loads(open(filename).read())
|
||||
|
||||
# Run test function until we get an result. Wait at most 60 seconds.
|
||||
test_func = partial(compare_json_test,
|
||||
tgen.gears[rname], command, expected, exact)
|
||||
_, diff = topotest.run_and_expect(test_func, None, count=120, wait=0.5)
|
||||
assertmsg = '"{}" JSON output mismatches the expected result'.format(rname)
|
||||
assert diff is None, assertmsg
|
||||
|
||||
def cmp_json_output_exact(rname, command, reference):
|
||||
return cmp_json_output(rname, command, reference, True)
|
||||
|
||||
def add_candidate_path(rname, endpoint, pref, name, segment_list='default'):
|
||||
get_topogen().net[rname].cmd(''' \
|
||||
vtysh -c "conf t" \
|
||||
-c "segment-routing" \
|
||||
-c "traffic-eng" \
|
||||
-c "policy color 1 endpoint ''' + endpoint + '''" \
|
||||
-c "candidate-path preference ''' + str(pref) + ''' name ''' + name + ''' explicit segment-list ''' + segment_list + '''"''')
|
||||
|
||||
def delete_candidate_path(rname, endpoint, pref):
|
||||
get_topogen().net[rname].cmd(''' \
|
||||
vtysh -c "conf t" \
|
||||
-c "segment-routing" \
|
||||
-c "traffic-eng" \
|
||||
-c "policy color 1 endpoint ''' + endpoint + '''" \
|
||||
-c "no candidate-path preference ''' + str(pref) + '''"''')
|
||||
|
||||
def add_segment(rname, name, index, label):
|
||||
get_topogen().net[rname].cmd(''' \
|
||||
vtysh -c "conf t" \
|
||||
-c "segment-routing" \
|
||||
-c "traffic-eng" \
|
||||
-c "segment-list ''' + name + '''" \
|
||||
-c "index ''' + str(index) + ''' mpls label ''' + str(label) + '''"''')
|
||||
|
||||
def delete_segment(rname, name, index):
|
||||
get_topogen().net[rname].cmd(''' \
|
||||
vtysh -c "conf t" \
|
||||
-c "segment-routing" \
|
||||
-c "traffic-eng" \
|
||||
-c "segment-list ''' + name + '''" \
|
||||
-c "no index ''' + str(index) + '''"''')
|
||||
|
||||
def create_sr_policy(rname, endpoint, bsid):
|
||||
get_topogen().net[rname].cmd(''' \
|
||||
vtysh -c "conf t" \
|
||||
-c "segment-routing" \
|
||||
-c "traffic-eng" \
|
||||
-c "policy color 1 endpoint ''' + endpoint + '''" \
|
||||
-c "name default" \
|
||||
-c "binding-sid ''' + str(bsid) + '''"''')
|
||||
|
||||
def delete_sr_policy(rname, endpoint):
|
||||
get_topogen().net[rname].cmd(''' \
|
||||
vtysh -c "conf t" \
|
||||
-c "segment-routing" \
|
||||
-c "traffic-eng" \
|
||||
-c "no policy color 1 endpoint ''' + endpoint + '''"''')
|
||||
|
||||
def create_prefix_sid(rname, prefix, sid):
|
||||
get_topogen().net[rname].cmd(''' \
|
||||
vtysh -c "conf t" \
|
||||
-c "router isis 1" \
|
||||
-c "segment-routing prefix ''' + prefix + " index " + str(sid) + '''"''')
|
||||
|
||||
def delete_prefix_sid(rname, prefix):
|
||||
get_topogen().net[rname].cmd(''' \
|
||||
vtysh -c "conf t" \
|
||||
-c "router isis 1" \
|
||||
-c "no segment-routing prefix "''' + prefix)
|
||||
|
||||
#
|
||||
# Step 1
|
||||
#
|
||||
# Checking the MPLS table using a single SR Policy and a single Candidate Path
|
||||
#
|
||||
def test_srte_init_step1():
|
||||
setup_testcase("Test (step 1): wait for IS-IS convergence / label distribution")
|
||||
|
||||
for rname in ['rt1', 'rt6']:
|
||||
cmp_json_output(rname,
|
||||
"show mpls table json",
|
||||
"step1/show_mpls_table_without_candidate.ref")
|
||||
|
||||
def test_srte_add_candidate_check_mpls_table_step1():
|
||||
setup_testcase("Test (step 1): check MPLS table regarding the added Candidate Path")
|
||||
|
||||
for rname, endpoint in [('rt1', '6.6.6.6'), ('rt6', '1.1.1.1')]:
|
||||
add_candidate_path(rname, endpoint, 100, 'default')
|
||||
cmp_json_output(rname,
|
||||
"show mpls table json",
|
||||
"step1/show_mpls_table_with_candidate.ref")
|
||||
delete_candidate_path(rname, endpoint, 100)
|
||||
|
||||
def test_srte_reinstall_sr_policy_check_mpls_table_step1():
|
||||
setup_testcase("Test (step 1): check MPLS table after the SR Policy was removed and reinstalled")
|
||||
|
||||
for rname, endpoint, bsid in [('rt1', '6.6.6.6', 1111), ('rt6', '1.1.1.1', 6666)]:
|
||||
add_candidate_path(rname, endpoint, 100, 'default')
|
||||
delete_sr_policy(rname, endpoint)
|
||||
cmp_json_output(rname,
|
||||
"show mpls table json",
|
||||
"step1/show_mpls_table_without_candidate.ref")
|
||||
create_sr_policy(rname, endpoint, bsid)
|
||||
add_candidate_path(rname, endpoint, 100, 'default')
|
||||
cmp_json_output(rname,
|
||||
"show mpls table json",
|
||||
"step1/show_mpls_table_with_candidate.ref")
|
||||
delete_candidate_path(rname, endpoint, 100)
|
||||
|
||||
#
|
||||
# Step 2
|
||||
#
|
||||
# Checking pathd operational data using a single SR Policy and a single Candidate Path
|
||||
#
|
||||
def test_srte_bare_policy_step2():
|
||||
setup_testcase("Test (step 2): bare SR Policy should not be operational")
|
||||
|
||||
for rname in ['rt1', 'rt6']:
|
||||
cmp_json_output_exact(rname,
|
||||
"show yang operational-data /frr-pathd:pathd pathd",
|
||||
"step2/show_operational_data.ref")
|
||||
|
||||
def test_srte_add_candidate_check_operational_data_step2():
|
||||
setup_testcase("Test (step 2): add single Candidate Path, SR Policy should be operational")
|
||||
|
||||
for rname, endpoint in [('rt1', '6.6.6.6'), ('rt6', '1.1.1.1')]:
|
||||
add_candidate_path(rname, endpoint, 100, 'default')
|
||||
cmp_json_output(rname,
|
||||
"show yang operational-data /frr-pathd:pathd pathd",
|
||||
"step2/show_operational_data_with_candidate.ref")
|
||||
|
||||
def test_srte_config_remove_candidate_check_operational_data_step2():
|
||||
setup_testcase("Test (step 2): remove single Candidate Path, SR Policy should not be operational anymore")
|
||||
|
||||
for rname, endpoint in [('rt1', '6.6.6.6'), ('rt6', '1.1.1.1')]:
|
||||
delete_candidate_path(rname, endpoint, 100)
|
||||
cmp_json_output_exact(rname,
|
||||
"show yang operational-data /frr-pathd:pathd pathd",
|
||||
"step2/show_operational_data.ref")
|
||||
|
||||
#
|
||||
# Step 3
|
||||
#
|
||||
# Testing the Candidate Path selection
|
||||
#
|
||||
def test_srte_add_two_candidates_step3():
|
||||
setup_testcase("Test (step 3): second Candidate Path has higher Priority")
|
||||
|
||||
for rname, endpoint in [('rt1', '6.6.6.6'), ('rt6', '1.1.1.1')]:
|
||||
for pref, cand_name in [('100', 'first'), ('200', 'second')]:
|
||||
add_candidate_path(rname, endpoint, pref, cand_name)
|
||||
cmp_json_output(rname,
|
||||
"show yang operational-data /frr-pathd:pathd pathd",
|
||||
"step3/show_operational_data_with_two_candidates.ref")
|
||||
|
||||
# cleanup
|
||||
for rname, endpoint in [('rt1', '6.6.6.6'), ('rt6', '1.1.1.1')]:
|
||||
for pref in ['100', '200']:
|
||||
delete_candidate_path(rname, endpoint, pref)
|
||||
|
||||
def test_srte_add_two_candidates_with_reverse_priority_step3():
|
||||
setup_testcase("Test (step 3): second Candidate Path has lower Priority")
|
||||
|
||||
# Use reversed priorities here
|
||||
for rname, endpoint in [('rt1', '6.6.6.6'), ('rt6', '1.1.1.1')]:
|
||||
for pref, cand_name in [('200', 'first'), ('100', 'second')]:
|
||||
add_candidate_path(rname, endpoint, pref, cand_name)
|
||||
cmp_json_output(rname,
|
||||
"show yang operational-data /frr-pathd:pathd pathd",
|
||||
"step3/show_operational_data_with_two_candidates.ref")
|
||||
|
||||
# cleanup
|
||||
for rname, endpoint in [('rt1', '6.6.6.6'), ('rt6', '1.1.1.1')]:
|
||||
for pref in ['100', '200']:
|
||||
delete_candidate_path(rname, endpoint, pref)
|
||||
|
||||
def test_srte_remove_best_candidate_step3():
|
||||
setup_testcase("Test (step 3): delete the Candidate Path with higher priority")
|
||||
|
||||
for rname, endpoint in [('rt1', '6.6.6.6'), ('rt6', '1.1.1.1')]:
|
||||
for pref, cand_name in [('100', 'first'), ('200', 'second')]:
|
||||
add_candidate_path(rname, endpoint, pref, cand_name)
|
||||
|
||||
# Delete candidate with higher priority
|
||||
for rname, endpoint in [('rt1', '6.6.6.6'), ('rt6', '1.1.1.1')]:
|
||||
delete_candidate_path(rname, endpoint, 200)
|
||||
|
||||
# Candidate with lower priority should get active now
|
||||
for rname, endpoint in [('rt1', '6.6.6.6'), ('rt6', '1.1.1.1')]:
|
||||
cmp_json_output(rname,
|
||||
"show yang operational-data /frr-pathd:pathd pathd",
|
||||
"step3/show_operational_data_with_single_candidate.ref")
|
||||
# cleanup
|
||||
delete_candidate_path(rname, endpoint, 100)
|
||||
|
||||
#
|
||||
# Step 4
|
||||
#
|
||||
# Checking MPLS table with a single SR Policy and a Candidate Path with different Segment Lists and other modifications
|
||||
#
|
||||
def test_srte_change_segment_list_check_mpls_table_step4():
|
||||
setup_testcase("Test (step 4): check MPLS table for changed Segment List")
|
||||
|
||||
for rname, endpoint in [('rt1', '6.6.6.6'), ('rt6', '1.1.1.1')]:
|
||||
add_candidate_path(rname, endpoint, 100, 'default')
|
||||
# now change the segment list name
|
||||
add_candidate_path(rname, endpoint, 100, 'default', 'test')
|
||||
cmp_json_output(rname,
|
||||
"show mpls table json",
|
||||
"step4/show_mpls_table.ref")
|
||||
delete_candidate_path(rname, endpoint, 100)
|
||||
|
||||
def test_srte_segment_list_add_segment_check_mpls_table_step4():
|
||||
setup_testcase("Test (step 4): check MPLS table for added (then changed and finally deleted) segment")
|
||||
|
||||
add_candidate_path('rt1', '6.6.6.6', 100, 'default', 'test')
|
||||
|
||||
# first add a new segment
|
||||
add_segment('rt1', 'test', 25, 16050)
|
||||
cmp_json_output('rt1',
|
||||
"show mpls table json",
|
||||
"step4/show_mpls_table_add_segment.ref")
|
||||
|
||||
# ... then change it ...
|
||||
add_segment('rt1', 'test', 25, 16030)
|
||||
cmp_json_output('rt1',
|
||||
"show mpls table json",
|
||||
"step4/show_mpls_table_change_segment.ref")
|
||||
|
||||
# ... and finally delete it
|
||||
delete_segment('rt1', 'test', 25)
|
||||
cmp_json_output('rt1',
|
||||
"show mpls table json",
|
||||
"step4/show_mpls_table.ref")
|
||||
delete_candidate_path('rt1', '6.6.6.6', 100)
|
||||
|
||||
#
|
||||
# Step 5
|
||||
#
|
||||
# Checking the nexthop using a single SR Policy and a Candidate Path with configured route-map
|
||||
#
|
||||
def test_srte_route_map_with_sr_policy_check_nextop_step5():
|
||||
setup_testcase("Test (step 5): recursive nexthop learned through BGP neighbour should be aligned with SR Policy from route-map")
|
||||
|
||||
# (re-)build the SR Policy two times to ensure that reinstalling still works
|
||||
for i in [1,2]:
|
||||
cmp_json_output('rt1',
|
||||
"show ip route bgp json",
|
||||
"step5/show_ip_route_bgp_inactive_srte.ref")
|
||||
|
||||
delete_sr_policy('rt1', '6.6.6.6')
|
||||
cmp_json_output('rt1',
|
||||
"show ip route bgp json",
|
||||
"step5/show_ip_route_bgp_inactive_srte.ref")
|
||||
|
||||
create_sr_policy('rt1', '6.6.6.6', 1111)
|
||||
cmp_json_output('rt1',
|
||||
"show ip route bgp json",
|
||||
"step5/show_ip_route_bgp_inactive_srte.ref")
|
||||
|
||||
add_candidate_path('rt1', '6.6.6.6', 100, 'default')
|
||||
cmp_json_output('rt1',
|
||||
"show ip route bgp json",
|
||||
"step5/show_ip_route_bgp_active_srte.ref")
|
||||
|
||||
delete_candidate_path('rt1', '6.6.6.6', 100)
|
||||
|
||||
def test_srte_route_map_with_sr_policy_reinstall_prefix_sid_check_nextop_step5():
|
||||
setup_testcase("Test (step 5): remove and re-install prefix SID on fist path element and check SR Policy activity")
|
||||
|
||||
# first add a candidate path so the SR Policy is active
|
||||
add_candidate_path('rt1', '6.6.6.6', 100, 'default')
|
||||
cmp_json_output('rt1',
|
||||
"show yang operational-data /frr-pathd:pathd pathd",
|
||||
"step5/show_operational_data_active.ref")
|
||||
|
||||
# delete prefix SID from first element of the configured path and check
|
||||
# if the SR Policy is inactive since the label can't be resolved anymore
|
||||
delete_prefix_sid('rt5', "5.5.5.5/32")
|
||||
cmp_json_output('rt1',
|
||||
"show yang operational-data /frr-pathd:pathd pathd",
|
||||
"step5/show_operational_data_inactive.ref")
|
||||
cmp_json_output('rt1',
|
||||
"show ip route bgp json",
|
||||
"step5/show_ip_route_bgp_inactive_srte.ref")
|
||||
|
||||
# re-create the prefix SID and check if the SR Policy is active
|
||||
create_prefix_sid('rt5', "5.5.5.5/32", 50)
|
||||
cmp_json_output('rt1',
|
||||
"show yang operational-data /frr-pathd:pathd pathd",
|
||||
"step5/show_operational_data_active.ref")
|
||||
cmp_json_output('rt1',
|
||||
"show ip route bgp json",
|
||||
"step5/show_ip_route_bgp_active_srte.ref")
|
||||
|
||||
# Memory leak test template
|
||||
def test_memory_leak():
|
||||
"Run the memory leak test and report results."
|
||||
tgen = get_topogen()
|
||||
if not tgen.is_memleak_enabled():
|
||||
pytest.skip('Memory leak test/report is disabled')
|
||||
|
||||
tgen.report_memory_leaks()
|
||||
|
||||
if __name__ == '__main__':
|
||||
args = ["-s"] + sys.argv[1:]
|
||||
sys.exit(pytest.main(args))
|
@ -552,6 +552,7 @@ class TopoRouter(TopoGear):
|
||||
RD_SHARP = 14
|
||||
RD_BABEL = 15
|
||||
RD_PBRD = 16
|
||||
RD_PATH = 17
|
||||
RD = {
|
||||
RD_ZEBRA: "zebra",
|
||||
RD_RIP: "ripd",
|
||||
@ -569,6 +570,7 @@ class TopoRouter(TopoGear):
|
||||
RD_SHARP: "sharpd",
|
||||
RD_BABEL: "babeld",
|
||||
RD_PBRD: "pbrd",
|
||||
RD_PATH: 'pathd',
|
||||
}
|
||||
|
||||
def __init__(self, tgen, cls, name, **params):
|
||||
|
@ -1096,6 +1096,7 @@ class Router(Node):
|
||||
"sharpd": 0,
|
||||
"babeld": 0,
|
||||
"pbrd": 0,
|
||||
'pathd': 0
|
||||
}
|
||||
self.daemons_options = {"zebra": ""}
|
||||
self.reportCores = True
|
||||
|
@ -626,6 +626,22 @@ end
|
||||
ctx_keys = []
|
||||
current_context_lines = []
|
||||
|
||||
elif (
|
||||
line == "exit"
|
||||
and len(ctx_keys) > 1
|
||||
and ctx_keys[0].startswith("segment-routing")
|
||||
):
|
||||
self.save_contexts(ctx_keys, current_context_lines)
|
||||
|
||||
# Start a new context
|
||||
ctx_keys = ctx_keys[:-1]
|
||||
current_context_lines = []
|
||||
log.debug(
|
||||
"LINE %-50s: popping segment routing sub-context to ctx%-50s",
|
||||
line,
|
||||
ctx_keys
|
||||
)
|
||||
|
||||
elif line in ["exit-address-family", "exit", "exit-vnc"]:
|
||||
# if this exit is for address-family ipv4 unicast, ignore the pop
|
||||
if main_ctx_key:
|
||||
@ -637,7 +653,7 @@ end
|
||||
log.debug(
|
||||
"LINE %-50s: popping from subcontext to ctx%-50s",
|
||||
line,
|
||||
ctx_keys,
|
||||
ctx_keys
|
||||
)
|
||||
|
||||
elif line in ["exit-vni", "exit-ldp-if"]:
|
||||
@ -665,6 +681,27 @@ end
|
||||
current_context_lines = []
|
||||
new_ctx = False
|
||||
log.debug("LINE %-50s: entering new context, %-50s", line, ctx_keys)
|
||||
|
||||
elif (
|
||||
line.startswith("peer ")
|
||||
and len(ctx_keys) == 4
|
||||
and ctx_keys[0].startswith("segment-routing")
|
||||
and ctx_keys[1].startswith("traffic-eng")
|
||||
and ctx_keys[2].startswith("pcep")
|
||||
and ctx_keys[3].startswith("pcc")
|
||||
):
|
||||
# If there is no precedence, we add the default one (255) so
|
||||
# the line is not removed and added back
|
||||
m = re.search('peer ([^ ]*)', line)
|
||||
if (m != None):
|
||||
(name,) = m.groups()
|
||||
line = "peer %s precedence 255" % (name,)
|
||||
|
||||
current_context_lines.append(line)
|
||||
log.debug(
|
||||
"LINE %-50s: append to current_context_lines, %-50s", line, ctx_keys
|
||||
)
|
||||
|
||||
elif (
|
||||
line.startswith("address-family ")
|
||||
or line.startswith("vnc defaults")
|
||||
@ -727,6 +764,135 @@ end
|
||||
)
|
||||
ctx_keys.append(line)
|
||||
|
||||
elif (
|
||||
line.startswith("traffic-eng")
|
||||
and len(ctx_keys) == 1
|
||||
and ctx_keys[0].startswith("segment-routing")
|
||||
):
|
||||
|
||||
# Save old context first
|
||||
self.save_contexts(ctx_keys, current_context_lines)
|
||||
current_context_lines = []
|
||||
log.debug(
|
||||
"LINE %-50s: entering segment routing sub-context, append to ctx_keys", line
|
||||
)
|
||||
ctx_keys.append(line)
|
||||
|
||||
elif (
|
||||
line.startswith("segment-list ")
|
||||
and len(ctx_keys) == 2
|
||||
and ctx_keys[0].startswith("segment-routing")
|
||||
and ctx_keys[1].startswith("traffic-eng")
|
||||
):
|
||||
|
||||
# Save old context first
|
||||
self.save_contexts(ctx_keys, current_context_lines)
|
||||
current_context_lines = []
|
||||
log.debug(
|
||||
"LINE %-50s: entering segment routing sub-context, append to ctx_keys", line
|
||||
)
|
||||
ctx_keys.append(line)
|
||||
|
||||
elif (
|
||||
line.startswith("policy ")
|
||||
and len(ctx_keys) == 2
|
||||
and ctx_keys[0].startswith("segment-routing")
|
||||
and ctx_keys[1].startswith("traffic-eng")
|
||||
):
|
||||
|
||||
# Save old context first
|
||||
self.save_contexts(ctx_keys, current_context_lines)
|
||||
current_context_lines = []
|
||||
log.debug(
|
||||
"LINE %-50s: entering segment routing sub-context, append to ctx_keys", line
|
||||
)
|
||||
ctx_keys.append(line)
|
||||
|
||||
elif (
|
||||
line.startswith("candidate-path ")
|
||||
and line.endswith(" dynamic")
|
||||
and len(ctx_keys) == 3
|
||||
and ctx_keys[0].startswith("segment-routing")
|
||||
and ctx_keys[1].startswith("traffic-eng")
|
||||
and ctx_keys[2].startswith("policy")
|
||||
):
|
||||
|
||||
# Save old context first
|
||||
self.save_contexts(ctx_keys, current_context_lines)
|
||||
current_context_lines = []
|
||||
main_ctx_key = copy.deepcopy(ctx_keys)
|
||||
log.debug(
|
||||
"LINE %-50s: entering candidate-path sub-context, append to ctx_keys", line
|
||||
)
|
||||
ctx_keys.append(line)
|
||||
|
||||
elif (
|
||||
line.startswith("pcep")
|
||||
and len(ctx_keys) == 2
|
||||
and ctx_keys[0].startswith("segment-routing")
|
||||
and ctx_keys[1].startswith("traffic-eng")
|
||||
):
|
||||
|
||||
# Save old context first
|
||||
self.save_contexts(ctx_keys, current_context_lines)
|
||||
current_context_lines = []
|
||||
main_ctx_key = copy.deepcopy(ctx_keys)
|
||||
log.debug(
|
||||
"LINE %-50s: entering pcep sub-context, append to ctx_keys", line
|
||||
)
|
||||
ctx_keys.append(line)
|
||||
|
||||
elif (
|
||||
line.startswith("pce-config ")
|
||||
and len(ctx_keys) == 3
|
||||
and ctx_keys[0].startswith("segment-routing")
|
||||
and ctx_keys[1].startswith("traffic-eng")
|
||||
and ctx_keys[2].startswith("pcep")
|
||||
):
|
||||
|
||||
# Save old context first
|
||||
self.save_contexts(ctx_keys, current_context_lines)
|
||||
current_context_lines = []
|
||||
main_ctx_key = copy.deepcopy(ctx_keys)
|
||||
log.debug(
|
||||
"LINE %-50s: entering pce-config sub-context, append to ctx_keys", line
|
||||
)
|
||||
ctx_keys.append(line)
|
||||
|
||||
elif (
|
||||
line.startswith("pce ")
|
||||
and len(ctx_keys) == 3
|
||||
and ctx_keys[0].startswith("segment-routing")
|
||||
and ctx_keys[1].startswith("traffic-eng")
|
||||
and ctx_keys[2].startswith("pcep")
|
||||
):
|
||||
|
||||
# Save old context first
|
||||
self.save_contexts(ctx_keys, current_context_lines)
|
||||
current_context_lines = []
|
||||
main_ctx_key = copy.deepcopy(ctx_keys)
|
||||
log.debug(
|
||||
"LINE %-50s: entering pce sub-context, append to ctx_keys", line
|
||||
)
|
||||
ctx_keys.append(line)
|
||||
|
||||
elif (
|
||||
line.startswith("pcc")
|
||||
and len(ctx_keys) == 3
|
||||
and ctx_keys[0].startswith("segment-routing")
|
||||
and ctx_keys[1].startswith("traffic-eng")
|
||||
and ctx_keys[2].startswith("pcep")
|
||||
):
|
||||
|
||||
# Save old context first
|
||||
self.save_contexts(ctx_keys, current_context_lines)
|
||||
current_context_lines = []
|
||||
main_ctx_key = copy.deepcopy(ctx_keys)
|
||||
log.debug(
|
||||
"LINE %-50s: entering pcc sub-context, append to ctx_keys", line
|
||||
)
|
||||
ctx_keys.append(line)
|
||||
|
||||
else:
|
||||
# Continuing in an existing context, add non-commented lines to it
|
||||
current_context_lines.append(line)
|
||||
@ -1244,6 +1410,9 @@ def compare_context_objects(newconf, running):
|
||||
# Compare the two Config objects to find the lines that we need to add/del
|
||||
lines_to_add = []
|
||||
lines_to_del = []
|
||||
pollist_to_del = []
|
||||
seglist_to_del = []
|
||||
candidates_to_add = []
|
||||
delete_bgpd = False
|
||||
|
||||
# Find contexts that are in newconf but not in running
|
||||
@ -1326,6 +1495,40 @@ def compare_context_objects(newconf, running):
|
||||
(running_ctx_keys[:1], None) in lines_to_del):
|
||||
continue
|
||||
|
||||
# Segment routing and traffic engineering never need to be deleted
|
||||
elif (
|
||||
len(running_ctx_keys) > 1
|
||||
and len(running_ctx_keys) < 3
|
||||
and running_ctx_keys[0].startswith('segment-routing')
|
||||
):
|
||||
continue
|
||||
|
||||
# Neither the pcep command
|
||||
elif (
|
||||
len(running_ctx_keys) == 3
|
||||
and running_ctx_keys[0].startswith('segment-routing')
|
||||
and running_ctx_keys[2].startswith('pcep4')
|
||||
):
|
||||
continue
|
||||
|
||||
# Segment lists can only be deleted after we removed all the candidate paths that
|
||||
# use them, so add them to a separate array that is going to be appended at the end
|
||||
elif (
|
||||
len(running_ctx_keys) == 3
|
||||
and running_ctx_keys[0].startswith('segment-routing')
|
||||
and running_ctx_keys[2].startswith('segment-list')
|
||||
):
|
||||
seglist_to_del.append((running_ctx_keys, None))
|
||||
|
||||
# Policies must be deleted after there candidate path, to be sure
|
||||
# we add them to a separate array that is going to be appended at the end
|
||||
elif (
|
||||
len(running_ctx_keys) == 3
|
||||
and running_ctx_keys[0].startswith('segment-routing')
|
||||
and running_ctx_keys[2].startswith('policy')
|
||||
):
|
||||
pollist_to_del.append((running_ctx_keys, None))
|
||||
|
||||
# Non-global context
|
||||
elif running_ctx_keys and not any(
|
||||
"address-family" in key for key in running_ctx_keys
|
||||
@ -1340,6 +1543,14 @@ def compare_context_objects(newconf, running):
|
||||
for line in running_ctx.lines:
|
||||
lines_to_del.append((running_ctx_keys, line))
|
||||
|
||||
# if we have some policies commands to delete, append them to lines_to_del
|
||||
if len(pollist_to_del) > 0:
|
||||
lines_to_del.extend(pollist_to_del)
|
||||
|
||||
# if we have some segment list commands to delete, append them to lines_to_del
|
||||
if len(seglist_to_del) > 0:
|
||||
lines_to_del.extend(seglist_to_del)
|
||||
|
||||
# Find the lines within each context to add
|
||||
# Find the lines within each context to del
|
||||
for (newconf_ctx_keys, newconf_ctx) in iteritems(newconf.contexts):
|
||||
@ -1349,7 +1560,19 @@ def compare_context_objects(newconf, running):
|
||||
|
||||
for line in newconf_ctx.lines:
|
||||
if line not in running_ctx.dlines:
|
||||
lines_to_add.append((newconf_ctx_keys, line))
|
||||
|
||||
# candidate paths can only be added after the policy and segment list,
|
||||
# so add them to a separate array that is going to be appended at the end
|
||||
if (
|
||||
len(newconf_ctx_keys) == 3
|
||||
and newconf_ctx_keys[0].startswith('segment-routing')
|
||||
and newconf_ctx_keys[2].startswith('policy ')
|
||||
and line.startswith('candidate-path ')
|
||||
):
|
||||
candidates_to_add.append((newconf_ctx_keys, line))
|
||||
|
||||
else:
|
||||
lines_to_add.append((newconf_ctx_keys, line))
|
||||
|
||||
for line in running_ctx.lines:
|
||||
if line not in newconf_ctx.dlines:
|
||||
@ -1358,10 +1581,27 @@ def compare_context_objects(newconf, running):
|
||||
for (newconf_ctx_keys, newconf_ctx) in iteritems(newconf.contexts):
|
||||
|
||||
if newconf_ctx_keys not in running.contexts:
|
||||
lines_to_add.append((newconf_ctx_keys, None))
|
||||
|
||||
for line in newconf_ctx.lines:
|
||||
lines_to_add.append((newconf_ctx_keys, line))
|
||||
# candidate paths can only be added after the policy and segment list,
|
||||
# so add them to a separate array that is going to be appended at the end
|
||||
if (
|
||||
len(newconf_ctx_keys) == 4
|
||||
and newconf_ctx_keys[0].startswith('segment-routing')
|
||||
and newconf_ctx_keys[3].startswith('candidate-path')
|
||||
):
|
||||
candidates_to_add.append((newconf_ctx_keys, None))
|
||||
for line in newconf_ctx.lines:
|
||||
candidates_to_add.append((newconf_ctx_keys, line))
|
||||
|
||||
else:
|
||||
lines_to_add.append((newconf_ctx_keys, None))
|
||||
|
||||
for line in newconf_ctx.lines:
|
||||
lines_to_add.append((newconf_ctx_keys, line))
|
||||
|
||||
# if we have some candidate paths commands to add, append them to lines_to_add
|
||||
if len(candidates_to_add) > 0:
|
||||
lines_to_add.extend(candidates_to_add)
|
||||
|
||||
(lines_to_add, lines_to_del) = check_for_exit_vrf(lines_to_add, lines_to_del)
|
||||
(lines_to_add, lines_to_del) = ignore_delete_re_add_lines(
|
||||
@ -1523,10 +1763,11 @@ if __name__ == "__main__":
|
||||
"staticd",
|
||||
"vrrpd",
|
||||
"ldpd",
|
||||
"pathd",
|
||||
]:
|
||||
log.error(
|
||||
"Daemon %s is not a valid option for 'show running-config'" % args.daemon
|
||||
)
|
||||
msg = "Daemon %s is not a valid option for 'show running-config'" % args.daemon
|
||||
print(msg)
|
||||
log.error(msg)
|
||||
sys.exit(1)
|
||||
|
||||
vtysh = Vtysh(args.bindir, args.confdir, args.vty_socket, args.pathspace)
|
||||
@ -1574,6 +1815,8 @@ if __name__ == "__main__":
|
||||
else:
|
||||
running.load_from_show_running(args.daemon)
|
||||
|
||||
|
||||
|
||||
(lines_to_add, lines_to_del) = compare_context_objects(newconf, running)
|
||||
lines_to_configure = []
|
||||
|
||||
|
@ -27,7 +27,7 @@ FRR_DEFAULT_PROFILE="@DFLT_NAME@" # traditional / datacenter
|
||||
# Local Daemon selection may be done by using /etc/frr/daemons.
|
||||
# See /usr/share/doc/frr/README.Debian.gz for further information.
|
||||
# Keep zebra first and do not list watchfrr!
|
||||
DAEMONS="zebra bgpd ripd ripngd ospfd ospf6d isisd babeld pimd ldpd nhrpd eigrpd sharpd pbrd staticd bfdd fabricd vrrpd"
|
||||
DAEMONS="zebra bgpd ripd ripngd ospfd ospf6d isisd babeld pimd ldpd nhrpd eigrpd sharpd pbrd staticd bfdd fabricd vrrpd pathd"
|
||||
MAX_INSTANCES=5
|
||||
RELOAD_SCRIPT="$D_PATH/frr-reload.py"
|
||||
|
||||
|
271
vtysh/vtysh.c
271
vtysh/vtysh.c
@ -139,6 +139,7 @@ struct vtysh_client vtysh_client[] = {
|
||||
{.fd = -1, .name = "staticd", .flag = VTYSH_STATICD, .next = NULL},
|
||||
{.fd = -1, .name = "bfdd", .flag = VTYSH_BFDD, .next = NULL},
|
||||
{.fd = -1, .name = "vrrpd", .flag = VTYSH_VRRPD, .next = NULL},
|
||||
{.fd = -1, .name = "pathd", .flag = VTYSH_PATHD, .next = NULL},
|
||||
};
|
||||
|
||||
/* Searches for client by name, returns index */
|
||||
@ -538,6 +539,15 @@ static int vtysh_execute_func(const char *line, int pager)
|
||||
|| saved_node == LDP_IPV6_IFACE_NODE)
|
||||
&& (tried == 1)) {
|
||||
vtysh_execute("exit");
|
||||
} else if ((saved_node == SR_SEGMENT_LIST_NODE
|
||||
|| saved_node == SR_POLICY_NODE
|
||||
|| saved_node == SR_CANDIDATE_DYN_NODE
|
||||
|| saved_node == PCEP_NODE
|
||||
|| saved_node == PCEP_PCE_CONFIG_NODE
|
||||
|| saved_node == PCEP_PCE_NODE
|
||||
|| saved_node == PCEP_PCC_NODE)
|
||||
&& (tried > 0)) {
|
||||
vtysh_execute("exit");
|
||||
} else if (tried) {
|
||||
vtysh_execute("end");
|
||||
vtysh_execute("configure");
|
||||
@ -689,6 +699,7 @@ int vtysh_mark_file(const char *filename)
|
||||
int ret;
|
||||
vector vline;
|
||||
int tried = 0;
|
||||
bool ending;
|
||||
const struct cmd_element *cmd;
|
||||
int saved_ret, prev_node;
|
||||
int lineno = 0;
|
||||
@ -740,6 +751,12 @@ int vtysh_mark_file(const char *filename)
|
||||
vty->node = LDP_L2VPN_NODE;
|
||||
}
|
||||
break;
|
||||
case SR_CANDIDATE_DYN_NODE:
|
||||
if (strncmp(vty_buf_copy, " ", 2)) {
|
||||
vty_out(vty, " exit\n");
|
||||
vty->node = SR_POLICY_NODE;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@ -812,6 +829,31 @@ int vtysh_mark_file(const char *filename)
|
||||
} else if ((prev_node == BFD_PEER_NODE)
|
||||
&& (tried == 1)) {
|
||||
vty_out(vty, "exit\n");
|
||||
} else if (((prev_node == SEGMENT_ROUTING_NODE)
|
||||
|| (prev_node == SR_TRAFFIC_ENG_NODE)
|
||||
|| (prev_node == SR_SEGMENT_LIST_NODE)
|
||||
|| (prev_node == SR_POLICY_NODE)
|
||||
|| (prev_node == SR_CANDIDATE_DYN_NODE)
|
||||
|| (prev_node == PCEP_NODE)
|
||||
|| (prev_node == PCEP_PCE_CONFIG_NODE)
|
||||
|| (prev_node == PCEP_PCE_NODE)
|
||||
|| (prev_node == PCEP_PCC_NODE))
|
||||
&& (tried > 0)) {
|
||||
ending = (vty->node != SEGMENT_ROUTING_NODE)
|
||||
&& (vty->node != SR_TRAFFIC_ENG_NODE)
|
||||
&& (vty->node != SR_SEGMENT_LIST_NODE)
|
||||
&& (vty->node != SR_POLICY_NODE)
|
||||
&& (vty->node != SR_CANDIDATE_DYN_NODE)
|
||||
&& (vty->node != PCEP_NODE)
|
||||
&& (vty->node != PCEP_PCE_CONFIG_NODE)
|
||||
&& (vty->node != PCEP_PCE_NODE)
|
||||
&& (vty->node != PCEP_PCC_NODE);
|
||||
if (ending)
|
||||
tried--;
|
||||
while (tried-- > 0)
|
||||
vty_out(vty, "exit\n");
|
||||
if (ending)
|
||||
vty_out(vty, "end\n");
|
||||
} else if (tried) {
|
||||
vty_out(vty, "end\n");
|
||||
}
|
||||
@ -1219,6 +1261,69 @@ static struct cmd_node pw_node = {
|
||||
.prompt = "%s(config-pw)# ",
|
||||
};
|
||||
|
||||
static struct cmd_node segment_routing_node = {
|
||||
.name = "segment-routing",
|
||||
.node = SEGMENT_ROUTING_NODE,
|
||||
.parent_node = CONFIG_NODE,
|
||||
.prompt = "%s(config-sr)# ",
|
||||
};
|
||||
|
||||
static struct cmd_node sr_traffic_eng_node = {
|
||||
.name = "sr traffic-eng",
|
||||
.node = SR_TRAFFIC_ENG_NODE,
|
||||
.parent_node = SEGMENT_ROUTING_NODE,
|
||||
.prompt = "%s(config-sr-te)# ",
|
||||
};
|
||||
|
||||
static struct cmd_node srte_segment_list_node = {
|
||||
.name = "srte segment-list",
|
||||
.node = SR_SEGMENT_LIST_NODE,
|
||||
.parent_node = SR_TRAFFIC_ENG_NODE,
|
||||
.prompt = "%s(config-sr-te-segment-list)# ",
|
||||
};
|
||||
|
||||
static struct cmd_node srte_policy_node = {
|
||||
.name = "srte policy",
|
||||
.node = SR_POLICY_NODE,
|
||||
.parent_node = SR_TRAFFIC_ENG_NODE,
|
||||
.prompt = "%s(config-sr-te-policy)# ",
|
||||
};
|
||||
|
||||
static struct cmd_node srte_candidate_dyn_node = {
|
||||
.name = "srte candidate-dyn",
|
||||
.node = SR_CANDIDATE_DYN_NODE,
|
||||
.parent_node = SR_POLICY_NODE,
|
||||
.prompt = "%s(config-sr-te-candidate)# ",
|
||||
};
|
||||
|
||||
static struct cmd_node pcep_node = {
|
||||
.name = "srte pcep",
|
||||
.node = PCEP_NODE,
|
||||
.parent_node = SR_TRAFFIC_ENG_NODE,
|
||||
.prompt = "%s(config-sr-te-pcep)# "
|
||||
};
|
||||
|
||||
static struct cmd_node pcep_pcc_node = {
|
||||
.name = "srte pcep pcc",
|
||||
.node = PCEP_PCC_NODE,
|
||||
.parent_node = PCEP_NODE,
|
||||
.prompt = "%s(config-sr-te-pcep-pcc)# ",
|
||||
};
|
||||
|
||||
static struct cmd_node pcep_pce_node = {
|
||||
.name = "srte pcep pce-peer",
|
||||
.node = PCEP_PCE_NODE,
|
||||
.parent_node = PCEP_NODE,
|
||||
.prompt = "%s(config-sr-te-pcep-pce-peer)# ",
|
||||
};
|
||||
|
||||
static struct cmd_node pcep_pce_config_node = {
|
||||
.name = "srte pcep pce-config",
|
||||
.node = PCEP_PCE_CONFIG_NODE,
|
||||
.parent_node = PCEP_NODE,
|
||||
.prompt = "%s(pcep-sr-te-pcep-pce-config)# ",
|
||||
};
|
||||
|
||||
static struct cmd_node vrf_node = {
|
||||
.name = "vrf",
|
||||
.node = VRF_NODE,
|
||||
@ -1974,6 +2079,102 @@ DEFUNSH(VTYSH_FABRICD, router_openfabric, router_openfabric_cmd, "router openfab
|
||||
}
|
||||
#endif /* HAVE_FABRICD */
|
||||
|
||||
#if defined(HAVE_PATHD)
|
||||
DEFUNSH(VTYSH_PATHD, segment_routing, segment_routing_cmd,
|
||||
"segment-routing",
|
||||
"Configure segment routing\n")
|
||||
{
|
||||
vty->node = SEGMENT_ROUTING_NODE;
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFUNSH(VTYSH_PATHD, sr_traffic_eng, sr_traffic_eng_cmd,
|
||||
"traffic-eng",
|
||||
"Configure SR traffic engineering\n")
|
||||
{
|
||||
vty->node = SR_TRAFFIC_ENG_NODE;
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFUNSH(VTYSH_PATHD, srte_segment_list, srte_segment_list_cmd,
|
||||
"segment-list WORD$name",
|
||||
"Segment List\n"
|
||||
"Segment List Name\n")
|
||||
{
|
||||
vty->node = SR_SEGMENT_LIST_NODE;
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFUNSH(VTYSH_PATHD, srte_policy, srte_policy_cmd,
|
||||
"policy color (0-4294967295) endpoint <A.B.C.D|X:X::X:X>",
|
||||
"Segment Routing Policy\n"
|
||||
"SR Policy color\n"
|
||||
"SR Policy color value\n"
|
||||
"SR Policy endpoint\n"
|
||||
"SR Policy endpoint IPv4 address\n"
|
||||
"SR Policy endpoint IPv6 address\n")
|
||||
{
|
||||
vty->node = SR_POLICY_NODE;
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFUNSH(VTYSH_PATHD, srte_policy_candidate_dyn_path,
|
||||
srte_policy_candidate_dyn_path_cmd,
|
||||
"candidate-path preference (0-4294967295) name WORD dynamic",
|
||||
"Segment Routing Policy Candidate Path\n"
|
||||
"Segment Routing Policy Candidate Path Preference\n"
|
||||
"Administrative Preference\n"
|
||||
"Segment Routing Policy Candidate Path Name\n"
|
||||
"Symbolic Name\n"
|
||||
"Dynamic Path\n")
|
||||
{
|
||||
vty->node = SR_CANDIDATE_DYN_NODE;
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
#if defined(HAVE_PATHD_PCEP)
|
||||
|
||||
DEFUNSH(VTYSH_PATHD, pcep, pcep_cmd,
|
||||
"pcep",
|
||||
"Configure SR pcep\n")
|
||||
{
|
||||
vty->node = PCEP_NODE;
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFUNSH(VTYSH_PATHD, pcep_cli_pcc, pcep_cli_pcc_cmd,
|
||||
"[no] pcc",
|
||||
NO_STR
|
||||
"PCC configuration\n")
|
||||
{
|
||||
vty->node = PCEP_PCC_NODE;
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFUNSH(VTYSH_PATHD, pcep_cli_pce, pcep_cli_pce_cmd,
|
||||
"[no] pce WORD",
|
||||
NO_STR
|
||||
"PCE configuration\n"
|
||||
"Peer name\n")
|
||||
{
|
||||
vty->node = PCEP_PCE_NODE;
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFUNSH(VTYSH_PATHD, pcep_cli_pcep_pce_config, pcep_cli_pcep_pce_config_cmd,
|
||||
"[no] pce-config WORD",
|
||||
NO_STR
|
||||
"PCEP peer Configuration Group\n"
|
||||
"PCEP peer Configuration Group name\n")
|
||||
{
|
||||
vty->node = PCEP_PCE_CONFIG_NODE;
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
#endif /* HAVE_PATHD_PCEP */
|
||||
|
||||
#endif /* HAVE_PATHD */
|
||||
|
||||
DEFUNSH(VTYSH_RMAP, vtysh_route_map, vtysh_route_map_cmd,
|
||||
"route-map WORD <deny|permit> (1-65535)",
|
||||
"Create route-map or enter route-map command mode\n"
|
||||
@ -2347,6 +2548,18 @@ DEFUNSH(VTYSH_KEYS, vtysh_quit_keys, vtysh_quit_keys_cmd, "quit",
|
||||
return vtysh_exit_keys(self, vty, argc, argv);
|
||||
}
|
||||
|
||||
DEFUNSH(VTYSH_PATHD, vtysh_exit_pathd, vtysh_exit_pathd_cmd, "exit",
|
||||
"Exit current mode and down to previous mode\n")
|
||||
{
|
||||
return vtysh_exit(vty);
|
||||
}
|
||||
|
||||
DEFUNSH(VTYSH_PATHD, vtysh_quit_pathd, vtysh_quit_pathd_cmd, "quit",
|
||||
"Exit current mode and down to previous mode\n")
|
||||
{
|
||||
return vtysh_exit_pathd(self, vty, argc, argv);
|
||||
}
|
||||
|
||||
DEFUNSH(VTYSH_ALL, vtysh_exit_line_vty, vtysh_exit_line_vty_cmd, "exit",
|
||||
"Exit current mode and down to previous mode\n")
|
||||
{
|
||||
@ -4144,6 +4357,64 @@ void vtysh_init_vty(void)
|
||||
install_element(BFD_PROFILE_NODE, &vtysh_end_all_cmd);
|
||||
#endif /* HAVE_BFDD */
|
||||
|
||||
#if defined(HAVE_PATHD)
|
||||
install_node(&segment_routing_node);
|
||||
install_node(&sr_traffic_eng_node);
|
||||
install_node(&srte_segment_list_node);
|
||||
install_node(&srte_policy_node);
|
||||
install_node(&srte_candidate_dyn_node);
|
||||
|
||||
install_element(SEGMENT_ROUTING_NODE, &vtysh_exit_pathd_cmd);
|
||||
install_element(SEGMENT_ROUTING_NODE, &vtysh_quit_pathd_cmd);
|
||||
install_element(SR_TRAFFIC_ENG_NODE, &vtysh_exit_pathd_cmd);
|
||||
install_element(SR_TRAFFIC_ENG_NODE, &vtysh_quit_pathd_cmd);
|
||||
install_element(SR_SEGMENT_LIST_NODE, &vtysh_exit_pathd_cmd);
|
||||
install_element(SR_SEGMENT_LIST_NODE, &vtysh_quit_pathd_cmd);
|
||||
install_element(SR_POLICY_NODE, &vtysh_exit_pathd_cmd);
|
||||
install_element(SR_POLICY_NODE, &vtysh_quit_pathd_cmd);
|
||||
install_element(SR_CANDIDATE_DYN_NODE, &vtysh_exit_pathd_cmd);
|
||||
install_element(SR_CANDIDATE_DYN_NODE, &vtysh_quit_pathd_cmd);
|
||||
|
||||
install_element(SEGMENT_ROUTING_NODE, &vtysh_end_all_cmd);
|
||||
install_element(SR_TRAFFIC_ENG_NODE, &vtysh_end_all_cmd);
|
||||
install_element(SR_SEGMENT_LIST_NODE, &vtysh_end_all_cmd);
|
||||
install_element(SR_POLICY_NODE, &vtysh_end_all_cmd);
|
||||
install_element(SR_CANDIDATE_DYN_NODE, &vtysh_end_all_cmd);
|
||||
|
||||
install_element(CONFIG_NODE, &segment_routing_cmd);
|
||||
install_element(SEGMENT_ROUTING_NODE, &sr_traffic_eng_cmd);
|
||||
install_element(SR_TRAFFIC_ENG_NODE, &srte_segment_list_cmd);
|
||||
install_element(SR_TRAFFIC_ENG_NODE, &srte_policy_cmd);
|
||||
install_element(SR_POLICY_NODE, &srte_policy_candidate_dyn_path_cmd);
|
||||
|
||||
#if defined(HAVE_PATHD_PCEP)
|
||||
install_node(&pcep_node);
|
||||
install_node(&pcep_pcc_node);
|
||||
install_node(&pcep_pce_node);
|
||||
install_node(&pcep_pce_config_node);
|
||||
|
||||
install_element(PCEP_NODE, &vtysh_exit_pathd_cmd);
|
||||
install_element(PCEP_NODE, &vtysh_quit_pathd_cmd);
|
||||
install_element(PCEP_PCC_NODE, &vtysh_exit_pathd_cmd);
|
||||
install_element(PCEP_PCC_NODE, &vtysh_quit_pathd_cmd);
|
||||
install_element(PCEP_PCE_NODE, &vtysh_exit_pathd_cmd);
|
||||
install_element(PCEP_PCE_NODE, &vtysh_quit_pathd_cmd);
|
||||
install_element(PCEP_PCE_CONFIG_NODE, &vtysh_exit_pathd_cmd);
|
||||
install_element(PCEP_PCE_CONFIG_NODE, &vtysh_quit_pathd_cmd);
|
||||
|
||||
install_element(PCEP_NODE, &vtysh_end_all_cmd);
|
||||
install_element(PCEP_PCC_NODE, &vtysh_end_all_cmd);
|
||||
install_element(PCEP_PCE_NODE, &vtysh_end_all_cmd);
|
||||
install_element(PCEP_PCE_CONFIG_NODE, &vtysh_end_all_cmd);
|
||||
|
||||
install_element(SR_TRAFFIC_ENG_NODE, &pcep_cmd);
|
||||
install_element(PCEP_NODE, &pcep_cli_pcc_cmd);
|
||||
install_element(PCEP_NODE, &pcep_cli_pcep_pce_config_cmd);
|
||||
install_element(PCEP_NODE, &pcep_cli_pce_cmd);
|
||||
#endif /* HAVE_PATHD_PCEP */
|
||||
|
||||
#endif /* HAVE_PATHD */
|
||||
|
||||
/* keychain */
|
||||
install_node(&keychain_node);
|
||||
install_element(CONFIG_NODE, &key_chain_cmd);
|
||||
|
@ -43,6 +43,7 @@ DECLARE_MGROUP(MVTYSH)
|
||||
#define VTYSH_BFDD 0x10000
|
||||
#define VTYSH_FABRICD 0x20000
|
||||
#define VTYSH_VRRPD 0x40000
|
||||
#define VTYSH_PATHD 0x80000
|
||||
|
||||
#define VTYSH_WAS_ACTIVE (-2)
|
||||
|
||||
@ -51,7 +52,7 @@ DECLARE_MGROUP(MVTYSH)
|
||||
/* watchfrr is not in ALL since library CLI functions should not be
|
||||
* run on it (logging & co. should stay in a fixed/frozen config, and
|
||||
* things like prefix lists are not even initialised) */
|
||||
#define VTYSH_ALL VTYSH_ZEBRA|VTYSH_RIPD|VTYSH_RIPNGD|VTYSH_OSPFD|VTYSH_OSPF6D|VTYSH_LDPD|VTYSH_BGPD|VTYSH_ISISD|VTYSH_PIMD|VTYSH_NHRPD|VTYSH_EIGRPD|VTYSH_BABELD|VTYSH_SHARPD|VTYSH_PBRD|VTYSH_STATICD|VTYSH_BFDD|VTYSH_FABRICD|VTYSH_VRRPD
|
||||
#define VTYSH_ALL VTYSH_ZEBRA|VTYSH_RIPD|VTYSH_RIPNGD|VTYSH_OSPFD|VTYSH_OSPF6D|VTYSH_LDPD|VTYSH_BGPD|VTYSH_ISISD|VTYSH_PIMD|VTYSH_NHRPD|VTYSH_EIGRPD|VTYSH_BABELD|VTYSH_SHARPD|VTYSH_PBRD|VTYSH_STATICD|VTYSH_BFDD|VTYSH_FABRICD|VTYSH_VRRPD|VTYSH_PATHD
|
||||
#define VTYSH_ACL VTYSH_BFDD|VTYSH_BABELD|VTYSH_BGPD|VTYSH_EIGRPD|VTYSH_ISISD|VTYSH_FABRICD|VTYSH_LDPD|VTYSH_NHRPD|VTYSH_OSPF6D|VTYSH_OSPFD|VTYSH_PBRD|VTYSH_PIMD|VTYSH_RIPD|VTYSH_RIPNGD|VTYSH_VRRPD|VTYSH_ZEBRA
|
||||
#define VTYSH_RMAP VTYSH_ZEBRA|VTYSH_RIPD|VTYSH_RIPNGD|VTYSH_OSPFD|VTYSH_OSPF6D|VTYSH_BGPD|VTYSH_ISISD|VTYSH_PIMD|VTYSH_EIGRPD|VTYSH_FABRICD
|
||||
#define VTYSH_INTERFACE VTYSH_ZEBRA|VTYSH_RIPD|VTYSH_RIPNGD|VTYSH_OSPFD|VTYSH_OSPF6D|VTYSH_ISISD|VTYSH_PIMD|VTYSH_NHRPD|VTYSH_EIGRPD|VTYSH_BABELD|VTYSH_PBRD|VTYSH_FABRICD|VTYSH_VRRPD
|
||||
|
480
yang/frr-pathd.yang
Normal file
480
yang/frr-pathd.yang
Normal file
@ -0,0 +1,480 @@
|
||||
module frr-pathd {
|
||||
yang-version 1.1;
|
||||
namespace "http://frrouting.org/yang/pathd";
|
||||
prefix frr-pathd;
|
||||
|
||||
import ietf-inet-types {
|
||||
prefix inet;
|
||||
}
|
||||
import ietf-yang-types {
|
||||
prefix yang;
|
||||
}
|
||||
import ietf-routing-types {
|
||||
prefix rt-types;
|
||||
}
|
||||
import frr-interface {
|
||||
prefix frr-interface;
|
||||
}
|
||||
|
||||
organization
|
||||
"Free Range Routing";
|
||||
contact
|
||||
"FRR Users List: <mailto:frog@lists.frrouting.org>
|
||||
FRR Development List: <mailto:dev@lists.frrouting.org>";
|
||||
description
|
||||
"This module defines a model for managing FRR pathd daemon.";
|
||||
|
||||
revision 2018-11-06 {
|
||||
description
|
||||
"Initial revision.";
|
||||
}
|
||||
|
||||
typedef protocol-origin-type {
|
||||
description
|
||||
"Indication for the protocol origin of an object.";
|
||||
type enumeration {
|
||||
enum pcep {
|
||||
value 1;
|
||||
description "The object was created through PCEP";
|
||||
}
|
||||
enum bgp {
|
||||
value 2;
|
||||
description "The object was created through GBP";
|
||||
}
|
||||
enum local {
|
||||
value 3;
|
||||
description "The object was created through CLI, Yang model via Netconf, gRPC, etc";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
typedef originator-type {
|
||||
type string {
|
||||
length "1..64";
|
||||
}
|
||||
description
|
||||
"Identifier of the originator of an object, could be 'config', '1.1.1.1:4189' or '2001:db8:85a3::8a2e:370:7334:4189'";
|
||||
}
|
||||
|
||||
container pathd {
|
||||
container srte {
|
||||
list segment-list {
|
||||
key "name";
|
||||
description "Segment-list properties";
|
||||
leaf name {
|
||||
type string {
|
||||
length "1..64";
|
||||
}
|
||||
description "Segment-list name";
|
||||
}
|
||||
leaf protocol-origin {
|
||||
type protocol-origin-type;
|
||||
mandatory true;
|
||||
description
|
||||
"Indication for the protocol origin of the segment list.";
|
||||
}
|
||||
leaf originator {
|
||||
type originator-type;
|
||||
mandatory true;
|
||||
description "Originator of the segment list";
|
||||
}
|
||||
list segment {
|
||||
key "index";
|
||||
description "Configure Segment/hop at the index";
|
||||
leaf index {
|
||||
type uint32;
|
||||
description "Segment index";
|
||||
}
|
||||
leaf sid-value {
|
||||
type rt-types:mpls-label;
|
||||
mandatory true;
|
||||
description "MPLS label value";
|
||||
}
|
||||
container nai {
|
||||
presence "The segement has a Node or Adjacency Identifier";
|
||||
leaf type {
|
||||
description "NAI type";
|
||||
mandatory true;
|
||||
type enumeration {
|
||||
enum ipv4_node {
|
||||
value 1;
|
||||
description "IPv4 node identifier";
|
||||
}
|
||||
enum ipv6_node {
|
||||
value 2;
|
||||
description "IPv6 node identifier";
|
||||
}
|
||||
enum ipv4_adjacency {
|
||||
value 3;
|
||||
description "IPv4 adjacency";
|
||||
}
|
||||
enum ipv6_adjacency {
|
||||
value 4;
|
||||
description "IPv6 adjacency";
|
||||
}
|
||||
enum ipv4_unnumbered_adjacency {
|
||||
value 5;
|
||||
description "IPv4 unnumbered adjacency";
|
||||
}
|
||||
}
|
||||
}
|
||||
leaf local-address {
|
||||
type inet:ip-address;
|
||||
mandatory true;
|
||||
}
|
||||
leaf local-interface {
|
||||
type uint32;
|
||||
mandatory true;
|
||||
when "../type = 'ipv4_unnumbered_adjacency'";
|
||||
}
|
||||
leaf remote-address {
|
||||
type inet:ip-address;
|
||||
mandatory true;
|
||||
when "../type = 'ipv4_adjacency' or ../type = 'ipv6_adjacency' or ../type = 'ipv4_unnumbered_adjacency'";
|
||||
}
|
||||
leaf remote-interface {
|
||||
type uint32;
|
||||
mandatory true;
|
||||
when "../type = 'ipv4_unnumbered_adjacency'";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
list policy {
|
||||
key "color endpoint";
|
||||
unique "name";
|
||||
leaf color {
|
||||
type uint32;
|
||||
description
|
||||
"Color of the SR Policy.";
|
||||
}
|
||||
leaf endpoint {
|
||||
type inet:ip-address;
|
||||
description
|
||||
"Indication for the endpoint of the SR Policy.";
|
||||
}
|
||||
leaf name {
|
||||
type string {
|
||||
length "1..64";
|
||||
}
|
||||
description
|
||||
"Name of the SR Policy.";
|
||||
}
|
||||
leaf binding-sid {
|
||||
type rt-types:mpls-label;
|
||||
description
|
||||
"BSID of the SR Policy.";
|
||||
}
|
||||
leaf is-operational {
|
||||
type boolean;
|
||||
config false;
|
||||
description
|
||||
"True if a valid candidate path of this policy is operational in zebra, False otherwise";
|
||||
}
|
||||
list candidate-path {
|
||||
unique "name";
|
||||
description
|
||||
"List of Candidate Paths of the SR Policy.";
|
||||
key "preference";
|
||||
leaf preference {
|
||||
type uint32;
|
||||
description
|
||||
"Administrative preference.";
|
||||
}
|
||||
leaf name {
|
||||
type string {
|
||||
length "1..64";
|
||||
}
|
||||
mandatory true;
|
||||
description
|
||||
"Symbolic Name of the Candidate Path.";
|
||||
}
|
||||
leaf is-best-candidate-path {
|
||||
type boolean;
|
||||
config false;
|
||||
description
|
||||
"True if the candidate path is the best candidate path, False otherwise";
|
||||
}
|
||||
leaf protocol-origin {
|
||||
type protocol-origin-type;
|
||||
mandatory true;
|
||||
description
|
||||
"Indication for the protocol origin of the Candidate Path.";
|
||||
}
|
||||
leaf originator {
|
||||
type originator-type;
|
||||
mandatory true;
|
||||
description "Originator of the candidate path";
|
||||
}
|
||||
leaf discriminator {
|
||||
type uint32;
|
||||
config false;
|
||||
description "Candidate path distinguisher";
|
||||
}
|
||||
leaf type {
|
||||
description
|
||||
"Type of the Candidate Path.";
|
||||
mandatory true;
|
||||
type enumeration {
|
||||
enum explicit {
|
||||
value 1;
|
||||
}
|
||||
enum dynamic {
|
||||
value 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
leaf segment-list-name {
|
||||
type leafref {
|
||||
path ../../../segment-list/name;
|
||||
}
|
||||
description
|
||||
"The name of the Segment List to use as LSP.";
|
||||
}
|
||||
container constraints {
|
||||
when "../type = 'dynamic'";
|
||||
description
|
||||
"Generic dynamic path constraints";
|
||||
container bandwidth {
|
||||
presence "If the candidate has a bandwidth constraint";
|
||||
description
|
||||
"The bandwidth needed by the candidate path.";
|
||||
leaf required {
|
||||
type boolean;
|
||||
default "true";
|
||||
description
|
||||
"If the bandwidth limitation is a requirement or only a suggestion";
|
||||
}
|
||||
leaf value {
|
||||
mandatory true;
|
||||
type decimal64 {
|
||||
fraction-digits 6;
|
||||
}
|
||||
}
|
||||
}
|
||||
container affinity {
|
||||
description
|
||||
"Affinity let you configure how the links should be used when calculating a path.";
|
||||
leaf exclude-any {
|
||||
type uint32;
|
||||
description
|
||||
"A 32-bit vector representing a set of attribute filters which renders a link unacceptable.";
|
||||
}
|
||||
leaf include-any {
|
||||
type uint32;
|
||||
description
|
||||
"A 32-bit vector representing a set of attribute filters which renders a link acceptable. A null set (all bits set to zero) automatically passes.";
|
||||
}
|
||||
leaf include-all {
|
||||
type uint32;
|
||||
description
|
||||
"A 32-bit vector representing a set of attribute filters which must be present for a link to be acceptable. A null set (all bits set to zero) automatically passes.";
|
||||
}
|
||||
}
|
||||
list metrics {
|
||||
key "type";
|
||||
leaf type {
|
||||
description
|
||||
"Type of the metric.";
|
||||
type enumeration {
|
||||
enum igp {
|
||||
value 1;
|
||||
description "IGP metric";
|
||||
}
|
||||
enum te {
|
||||
value 2;
|
||||
description "TE metric";
|
||||
}
|
||||
enum hc {
|
||||
value 3;
|
||||
description "Hop Counts";
|
||||
}
|
||||
enum abc {
|
||||
value 4;
|
||||
description "Aggregate bandwidth consumption";
|
||||
}
|
||||
enum lmll {
|
||||
value 5;
|
||||
description "Load of the most loaded link";
|
||||
}
|
||||
enum cigp {
|
||||
value 6;
|
||||
description "Cumulative IGP cost";
|
||||
}
|
||||
enum cte {
|
||||
value 7;
|
||||
description "Cumulative TE cost";
|
||||
}
|
||||
enum pigp {
|
||||
value 8;
|
||||
description "P2MP IGP metric";
|
||||
}
|
||||
enum pte {
|
||||
value 9;
|
||||
description "P2MP TE metric";
|
||||
}
|
||||
enum phc {
|
||||
value 10;
|
||||
description "P2MP hop count metric";
|
||||
}
|
||||
enum msd {
|
||||
value 11;
|
||||
description "Segment-ID (SID) Depth";
|
||||
}
|
||||
enum pd {
|
||||
value 12;
|
||||
description "Path Delay metric";
|
||||
}
|
||||
enum pdv {
|
||||
value 13;
|
||||
description "Path Delay Variation metric";
|
||||
}
|
||||
enum pl {
|
||||
value 14;
|
||||
description "Path Loss metric";
|
||||
}
|
||||
enum ppd {
|
||||
value 15;
|
||||
description "P2MP Path Delay metric";
|
||||
}
|
||||
enum ppdv {
|
||||
value 16;
|
||||
description "P2MP Path Delay variation metric";
|
||||
}
|
||||
enum ppl {
|
||||
value 17;
|
||||
description "P2MP Path Loss metric";
|
||||
}
|
||||
enum nap {
|
||||
value 18;
|
||||
description "Number of adaptations on a path";
|
||||
}
|
||||
enum nlp {
|
||||
value 19;
|
||||
description "Number of layers on a path";
|
||||
}
|
||||
enum dc {
|
||||
value 20;
|
||||
description "Domain Count metric";
|
||||
}
|
||||
enum bnc {
|
||||
value 21;
|
||||
description "Border Node Count metric";
|
||||
}
|
||||
}
|
||||
}
|
||||
leaf required {
|
||||
type boolean;
|
||||
default "true";
|
||||
description
|
||||
"If the metric is a requirement, or if it is only a suggestion";
|
||||
}
|
||||
leaf is-bound {
|
||||
type boolean;
|
||||
description
|
||||
"Defines if the value is a bound (a maximum) for the path metric that must not be exceeded.";
|
||||
}
|
||||
leaf is-computed {
|
||||
type boolean;
|
||||
description
|
||||
"Defines if the value has been generated by the originator of the path.";
|
||||
}
|
||||
leaf value {
|
||||
mandatory true;
|
||||
type decimal64 {
|
||||
fraction-digits 6;
|
||||
}
|
||||
}
|
||||
}
|
||||
container objective-function {
|
||||
presence "If the candidate has an objective function constraint";
|
||||
description
|
||||
"Define objective function constraint as a list of prefered functions";
|
||||
leaf required {
|
||||
type boolean;
|
||||
default "true";
|
||||
description
|
||||
"If an objective function is a requirement, or if it is only a suggestion";
|
||||
}
|
||||
leaf type {
|
||||
description
|
||||
"Type of objective function.";
|
||||
mandatory true;
|
||||
type enumeration {
|
||||
enum mcp {
|
||||
value 1;
|
||||
description "Minimum Cost Path";
|
||||
}
|
||||
enum mlp {
|
||||
value 2;
|
||||
description "Minimum Load Path";
|
||||
}
|
||||
enum mbp {
|
||||
value 3;
|
||||
description "Maximum residual Bandwidth Path";
|
||||
}
|
||||
enum mbc {
|
||||
value 4;
|
||||
description "Minimize aggregate Bandwidth Consumption";
|
||||
}
|
||||
enum mll {
|
||||
value 5;
|
||||
description "Minimize the Load of the most loaded Link";
|
||||
}
|
||||
enum mcc {
|
||||
value 6;
|
||||
description "Minimize the Cumulative Cost of a set of paths";
|
||||
}
|
||||
enum spt {
|
||||
value 7;
|
||||
description "Shortest Path Tree";
|
||||
}
|
||||
enum mct {
|
||||
value 8;
|
||||
description "Minimum Cost Tree";
|
||||
}
|
||||
enum mplp {
|
||||
value 9;
|
||||
description "Minimum Packet Loss Path";
|
||||
}
|
||||
enum mup {
|
||||
value 10;
|
||||
description "Maximum Under-Utilized Path";
|
||||
}
|
||||
enum mrup {
|
||||
value 11;
|
||||
description "Maximum Reserved Under-Utilized Path";
|
||||
}
|
||||
enum mtd {
|
||||
value 12;
|
||||
description "Minimize the number of Transit Domains";
|
||||
}
|
||||
enum mbn {
|
||||
value 13;
|
||||
description "Minimize the number of Border Nodes";
|
||||
}
|
||||
enum mctd {
|
||||
value 14;
|
||||
description "Minimize the number of Common Transit Domains";
|
||||
}
|
||||
enum msl {
|
||||
value 15;
|
||||
description "Minimize the number of Shared Links";
|
||||
}
|
||||
enum mss {
|
||||
value 16;
|
||||
description "Minimize the number of Shared SRLGs";
|
||||
}
|
||||
enum msn {
|
||||
value 17;
|
||||
description "Minimize the number of Shared Nodes";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -82,3 +82,7 @@ dist_yangmodels_DATA += yang/frr-bgp-bmp.yang
|
||||
dist_yangmodels_DATA += yang/frr-bgp-types.yang
|
||||
dist_yangmodels_DATA += yang/frr-bgp.yang
|
||||
endif
|
||||
|
||||
if PATHD
|
||||
dist_yangmodels_DATA += yang/frr-pathd.yang
|
||||
endif
|
||||
|
Loading…
Reference in New Issue
Block a user