mirror of
https://git.proxmox.com/git/mirror_frr
synced 2025-04-28 11:50:21 +00:00
pathd: Add optional support for PCEP to pathd
This new dynamic module makes pathd behave as a PCC for dynamic candidate path using the external library pcpelib https://github.com/volta-networks/pceplib . The candidate paths defined as dynamic will trigger computation requests to the configured PCE, and the PCE response will be used to update the policy. It supports multiple PCE. The one with smaller precedence will be elected as the master PCE, and only if the connection repeatedly fails, the PCC will switch to another PCE. Example of configuration: segment-routing traffic-eng pcep pce-config CONF source-address ip 10.10.10.10 sr-draft07 ! pce PCE1 config CONF address ip 1.1.1.1 ! pce PCE2 config CONF address ip 2.2.2.2 ! pcc peer PCE1 precedence 10 peer PCE2 precedence 20 ! ! ! ! Co-authored-by: Brady Johnson <brady@voltanet.io> Co-authored-by: Emanuele Di Pascale <emanuele@voltanet.io> Co-authored-by: GalaxyGorilla <sascha@netdef.org> Co-authored-by: Javier Garcia <javier.garcia@voltanet.io> Co-authored-by: Renato Westphal <renato@opensourcerouting.org> Co-authored-by: Sebastien Merle <sebastien@netdef.org> Signed-off-by: Sebastien Merle <sebastien@netdef.org>
This commit is contained in:
parent
4d7b695d3a
commit
efba0985fc
18
configure.ac
18
configure.ac
@ -627,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],
|
||||
@ -1681,6 +1683,10 @@ 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
|
||||
@ -2473,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"])
|
||||
|
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.
|
@ -8,3 +8,4 @@ Internals
|
||||
:maxdepth: 2
|
||||
|
||||
path-internals-daemon
|
||||
path-internals-pcep
|
||||
|
@ -47,6 +47,7 @@ dev_RSTFILES = \
|
||||
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 \
|
||||
|
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 |
@ -25,6 +25,33 @@ present and the :file:`frr.conf` is read instead.
|
||||
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
|
||||
===================
|
||||
|
||||
@ -32,6 +59,7 @@ Example:
|
||||
|
||||
.. code-block:: frr
|
||||
|
||||
debug pathd pcep basic
|
||||
segment-routing
|
||||
traffic-eng
|
||||
segment-list SL1
|
||||
@ -49,6 +77,25 @@ Example:
|
||||
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
|
||||
!
|
||||
!
|
||||
!
|
||||
!
|
||||
|
||||
@ -177,6 +224,121 @@ Configuration Commands
|
||||
- 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
|
||||
----------------------
|
||||
|
||||
@ -206,6 +368,54 @@ The asterisk (*) marks the best, e.g. active, candidate path. Note that for segm
|
||||
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
|
||||
=========================
|
||||
|
||||
|
@ -875,6 +875,18 @@ enum node_type node_parent(enum node_type node)
|
||||
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;
|
||||
|
@ -150,6 +150,10 @@ enum node_type {
|
||||
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 */
|
||||
|
@ -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
|
||||
};
|
||||
|
@ -24,15 +24,106 @@
|
||||
|
||||
/* 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 */
|
||||
|
||||
|
@ -23,6 +23,21 @@
|
||||
|
||||
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);
|
||||
|
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_
|
@ -29,5 +29,13 @@ segment-routing
|
||||
metric te 10
|
||||
!
|
||||
!
|
||||
pcep
|
||||
pcc-peer PCE1
|
||||
address ip 127.0.0.1
|
||||
sr-draft07
|
||||
!
|
||||
pcc
|
||||
peer PCE1
|
||||
!
|
||||
!
|
||||
!
|
||||
|
@ -10,6 +10,12 @@ 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 = \
|
||||
@ -29,20 +35,45 @@ 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/path_cli_clippy.c: $(CLIPPY_DEPS)
|
||||
pathd/path_cli.$(OBJEXT): pathd/path_cli_clippy.c
|
||||
|
||||
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@
|
||||
|
@ -681,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")
|
||||
@ -805,6 +826,73 @@ end
|
||||
)
|
||||
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)
|
||||
@ -1415,6 +1503,14 @@ def compare_context_objects(newconf, running):
|
||||
):
|
||||
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 (
|
||||
|
129
vtysh/vtysh.c
129
vtysh/vtysh.c
@ -541,8 +541,12 @@ static int vtysh_execute_func(const char *line, int pager)
|
||||
vtysh_execute("exit");
|
||||
} else if ((saved_node == SR_SEGMENT_LIST_NODE
|
||||
|| saved_node == SR_POLICY_NODE
|
||||
|| saved_node == SR_CANDIDATE_DYN_NODE)
|
||||
&& (tried > 0)) {
|
||||
|| 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");
|
||||
@ -826,16 +830,24 @@ int vtysh_mark_file(const char *filename)
|
||||
&& (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 == 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 != 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)
|
||||
@ -1284,6 +1296,34 @@ static struct cmd_node srte_candidate_dyn_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,
|
||||
@ -2091,6 +2131,48 @@ DEFUNSH(VTYSH_PATHD, srte_policy_candidate_dyn_path,
|
||||
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,
|
||||
@ -4304,6 +4386,33 @@ void vtysh_init_vty(void)
|
||||
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 */
|
||||
|
Loading…
Reference in New Issue
Block a user