pathd: New SR-TE policy management daemon

This new daemon manages Segment-Routing Traffic-Engineering
(SR-TE) Policies and installs them into zebra. It provides
the usual yang support and vtysh commands to define or change
SR-TE Policies.

In a nutshell SR-TE Policies provide the possibility to steer
traffic through a (possibly dynamic) list of Segment Routing
segments to the endpoint of the policy. This list of segments
is part of a Candidate Path which again belongs to the SR-TE
Policy. SR-TE Policies are uniquely identified by their color
and endpoint. The color can be used to e.g. match BGP
communities on incoming traffic.

There can be multiple Candidate Paths for a single
policy, the active Candidate Path is chosen according to
certain conditions of which the most important is its
preference. Candidate Paths can be explicit (fixed list of
segments) or dynamic (list of segment comes from e.g. PCEP, see
below).

Configuration example:

segment-routing
 traffic-eng
  segment-list SL
   index 10 mpls label 1111
   index 20 mpls label 2222
  !
  policy color 4 endpoint 10.10.10.4
   name POL4
   binding-sid 104
   candidate-path preference 100 name exp explicit segment-list SL
   candidate-path preference 200 name dyn dynamic
  !
 !
!

There is an important connection between dynamic Candidate
Paths and the overall topic of Path Computation. Later on for
pathd a dynamic module will be introduced that is capable
of communicating via the PCEP protocol with a PCE (Path
Computation Element) which again is capable of calculating
paths according to its local TED (Traffic Engineering Database).
This dynamic module will be able to inject the mentioned
dynamic Candidate Paths into pathd based on calculated paths
from a PCE.

https://tools.ietf.org/html/draft-ietf-spring-segment-routing-policy-06

Co-authored-by: Sebastien Merle <sebastien@netdef.org>
Co-authored-by: Renato Westphal <renato@opensourcerouting.org>
Co-authored-by: GalaxyGorilla <sascha@netdef.org>
Co-authored-by: Emanuele Di Pascale <emanuele@voltanet.io>
Signed-off-by: Sebastien Merle <sebastien@netdef.org>
This commit is contained in:
Sebastien Merle 2020-07-31 18:04:20 +02:00
parent 30ff2a502e
commit 4d7b695d3a
81 changed files with 7828 additions and 12 deletions

View File

@ -158,6 +158,7 @@ include bfdd/subdir.am
include yang/subdir.am
include yang/libyang_plugins/subdir.am
include vrrpd/subdir.am
include pathd/subdir.am
include vtysh/subdir.am
include tests/subdir.am

View File

@ -560,6 +560,8 @@ AC_ARG_ENABLE([fabricd],
AS_HELP_STRING([--disable-fabricd], [do not build fabricd]))
AC_ARG_ENABLE([vrrpd],
AS_HELP_STRING([--disable-vrrpd], [do not build vrrpd]))
AC_ARG_ENABLE([pathd],
AS_HELP_STRING([--disable-pathd], [do not build pathd]))
AC_ARG_ENABLE([bgp-announce],
AS_HELP_STRING([--disable-bgp-announce], [turn off BGP route announcement]))
AC_ARG_ENABLE([bgp-vnc],
@ -1675,6 +1677,10 @@ else
esac
fi
AS_IF([test "$enable_pathd" != "no"], [
AC_DEFINE([HAVE_PATHD], [1], [pathd])
])
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
@ -2489,6 +2495,7 @@ AM_CONDITIONAL([SHARPD], [test "$enable_sharpd" = "yes"])
AM_CONDITIONAL([STATICD], [test "$enable_staticd" != "no"])
AM_CONDITIONAL([FABRICD], [test "$enable_fabricd" != "no"])
AM_CONDITIONAL([VRRPD], [test "$enable_vrrpd" != "no"])
AM_CONDITIONAL([PATHD], [test "$enable_pathd" != "no"])
AC_CONFIG_FILES([Makefile],[
test "$enable_dev_build" = "yes" && makefile_devbuild="--dev-build"

View File

@ -18,3 +18,4 @@ FRRouting Developer's Guide
ospf
zebra
vtysh
pathd

View File

@ -0,0 +1,115 @@
PATHD Internals
===============
Architecture
------------
Overview
........
The pathd deamon manages the segment routing policies, it owns the data
structures representing them and can load modules that manipulate them like the
PCEP module. Its responsibility is to select a candidate path for each
configured policy and to install it into Zebra.
Zebra
.....
Zebra manages policies that are active or pending to be activated due to the
next hop not being available yet. In zebra, policy data structures and APIs are
defined in `zebra_srte.[hc]`.
The responsibilities of Zebra are:
- Store the policies' segment list.
- Install the policies when their next-hop is available.
- Notify other daemons of the status of the policies.
Adding and removing policies is done using the commands `ZEBRA_SR_POLICY_SET`
and `ZEBRA_SR_POLICY_DELETE` as parameter of the function `zebra_send_sr_policy`
all defined in `zclient.[hc]`.
If the first segment of the policy is an unknown label, it is kept until
notified by the mpls hooks `zebra_mpls_label_created`, and then it is installed.
To get notified when a policy status changes, a client can implement the
`sr_policy_notify_status` callback defined in `zclient.[hc]`.
For encoding/decoding the various data structures used to comunicate with zebra,
the following functions are available from `zclient.[hc]`:
`zapi_sr_policy_encode`, `zapi_sr_policy_decode` and
`zapi_sr_policy_notify_status_decode`.
Pathd
.....
The pathd daemon manages all the possible candidate paths for the segment
routing policies and selects the best one following the
`segment routing policy draft <https://tools.ietf.org/html/draft-ietf-spring-segment-routing-policy-06#section-2.9>`_.
It also supports loadable modules for handling dynamic candidate paths and the
creation of new policies and candidate paths at runtime.
The responsibilities of the pathd base daemon, not including any optional
modules, are:
- Store the policies and all the possible candidate paths for them.
- Select the best candidate path for each policy and send it to Zebra.
- Provide VTYSH configuration to set up policies and candidate paths.
- Provide a Northbound API to manipulate **configured** policies and candidate paths.
- Handle loadable modules for extending the functionality.
- Provide an API to the loadable module to manipulate policies and candidate paths.
Threading Model
---------------
The daemon runs completely inside the main thread using FRR event model, there
is no threading involved.
Source Code
-----------
Internal Data Structures
........................
The main data structures for policies and candidate paths are defined in
`pathd.h` and implemented in `pathd.c`.
When modifying these structures, either directly or through the functions
exported by `pathd.h`, nothing should be deleted/freed right away. The deletion
or modification flags must be set and when all the changes are done, the
function `srte_apply_changes` must be called. When called, a new candidate path
may be elected and sent to Zebra, and all the structures flagged as deleted
will be freed. In addition, a hook will be called so dynamic modules can perform
any required action when the elected candidate path changes.
Northbound API
..............
The northbound API is defined in `path_nb.[ch]` and implemented in
`path_nb_config.c` for configuration data and `path_nb_state.c` for operational
data.
Command Line Client
...................
The command-line client (VTYSH) is implemented in `path_cli.c`.
Interface with Zebra
....................
All the functions interfacing with Zebra are defined and implemented in
`path_zebra.[hc]`.
Loadable Module API
...................
For the time being, the API the loadable module uses is defined by `pathd.h`,
but in the future, it should be moved to a dedicated include file.

View File

@ -0,0 +1,10 @@
.. _path_internals:
*********
Internals
*********
.. toctree::
:maxdepth: 2
path-internals-daemon

11
doc/developer/path.rst Normal file
View File

@ -0,0 +1,11 @@
.. _path:
*****
PATHD
*****
.. toctree::
:maxdepth: 2
path-internals

View File

@ -46,6 +46,9 @@ dev_RSTFILES = \
doc/developer/packaging-debian.rst \
doc/developer/packaging-redhat.rst \
doc/developer/packaging.rst \
doc/developer/path-internals-daemon.rst \
doc/developer/path-internals.rst \
doc/developer/path.rst \
doc/developer/rcu.rst \
doc/developer/static-linking.rst \
doc/developer/testing.rst \

View File

@ -50,6 +50,7 @@ Protocols
nhrpd
ospfd
ospf6d
pathd
pim
pbr
ripd

233
doc/user/pathd.rst Normal file
View File

@ -0,0 +1,233 @@
.. _path:
****
PATH
****
:abbr:`PATH` is a daemon that handles the installation and deletion
of Segment Routing (SR) Policies.
.. _starting-path:
Starting PATH
=============
Default configuration file for *pathd* is :file:`pathd.conf`. The typical
location of :file:`pathd.conf` is |INSTALL_PREFIX_ETC|/pathd.conf.
If the user is using integrated config, then :file:`pathd.conf` need not be
present and the :file:`frr.conf` is read instead.
.. program:: pathd
:abbr:`PATH` supports all the common FRR daemon start options which are
documented elsewhere.
Pathd Configuration
===================
Example:
.. code-block:: frr
segment-routing
traffic-eng
segment-list SL1
index 10 mpls label 16010
index 20 mpls label 16030
!
policy color 1 endpoint 1.1.1.1
name default
binding-sid 4000
candidate-path preference 100 name CP1 explicit segment-list SL1
candidate-path preference 200 name CP2 dynamic
affinity include-any 0x000000FF
bandwidth 100000
metric bound msd 16 required
metric te 10
objective-function mcp required
!
!
!
.. _path-commands:
Configuration Commands
----------------------
.. index:: segment-routing
.. clicmd:: segment-routing
Configure segment routing.
.. index:: traffic-eng
.. clicmd:: traffic-eng
Configure segment routing traffic engineering.
.. index:: [no] segment-list NAME
.. clicmd:: [no] segment-list NAME
Delete or start a segment list definition.
.. index:: [no] index INDEX mpls label LABEL [nai node ADDRESS]
.. clicmd:: [no] index INDEX mpls label LABEL [nai node ADDRESS]
Delete or specify a segment in a segment list definition.
.. index:: [no] policy color COLOR endpoint ENDPOINT
.. clicmd:: [no] policy color COLOR endpoint ENDPOINT
Delete or start a policy definition.
.. index:: name NAME
.. clicmd:: name NAME
Specify the policy name.
.. index:: binding-sid LABEL
.. clicmd:: binding-sid LABEL
Specify the policy SID.
.. index:: [no] candidate-path preference PREFERENCE name NAME explicit segment-list SEGMENT-LIST-NAME
.. clicmd:: [no] candidate-path preference PREFERENCE name NAME explicit segment-list SEGMENT-LIST-NAME
Delete or define an explicit candidate path.
.. index:: [no] candidate-path preference PREFERENCE name NAME dynamic
.. clicmd:: [no] candidate-path preference PREFERENCE name NAME dynamic
Delete or start a dynamic candidate path definition.
.. index:: [no] affinity {exclude-any|include-any|include-all} BITPATTERN
.. clicmd:: [no] affinity {exclude-any|include-any|include-all} BITPATTERN
Delete or specify an affinity constraint for a dynamic candidate path.
.. index:: [no] bandwidth BANDWIDTH [required]
.. clicmd:: [no] bandwidth BANDWIDTH [required]
Delete or specify a bandwidth constraint for a dynamic candidate path.
.. index:: [no] metric [bound] METRIC VALUE [required]
.. clicmd:: [no] metric [bound] METRIC VALUE [required]
Delete or specify a metric constraint for a dynamic candidate path.
The possible metrics are:
- igp: IGP metric
- te: TE metric
- hc: Hop Counts
- abc: Aggregate bandwidth consumption
- mll: Load of the most loaded link
- igp: Cumulative IGP cost
- cte: Cumulative TE cost
- igp: P2MP IGP metric
- pte: P2MP TE metric
- phc: P2MP hop count metric
- msd: Segment-ID (SID) Depth
- pd: Path Delay metric
- pdv: Path Delay Variation metric
- pl: Path Loss metric
- ppd: P2MP Path Delay metric
- pdv: P2MP Path Delay variation metric
- ppl: P2MP Path Loss metric
- nap: Number of adaptations on a path
- nlp: Number of layers on a path
- dc: Domain Count metric
- bnc: Border Node Count metric
.. index:: [no] objective-function OBJFUN1 [required]
.. clicmd:: [no] objective-function OBJFUN1 [required]
Delete or specify a PCEP objective function constraint for a dynamic
candidate path.
The possible functions are:
- mcp: Minimum Cost Path [RFC5541]
- mlp: Minimum Load Path [RFC5541]
- mbp: Maximum residual Bandwidth Path [RFC5541]
- mbc: Minimize aggregate Bandwidth Consumption [RFC5541]
- mll: Minimize the Load of the most loaded Link [RFC5541]
- mcc: Minimize the Cumulative Cost of a set of paths [RFC5541]
- spt: Shortest Path Tree [RFC8306]
- mct: Minimum Cost Tree [RFC8306]
- mplp: Minimum Packet Loss Path [RFC8233]
- mup: Maximum Under-Utilized Path [RFC8233]
- mrup: Maximum Reserved Under-Utilized Path [RFC8233]
- mtd: Minimize the number of Transit Domains [RFC8685]
- mbn: Minimize the number of Border Nodes [RFC8685]
- mctd: Minimize the number of Common Transit Domains [RFC8685]
- msl: Minimize the number of Shared Links [RFC8800]
- mss: Minimize the number of Shared SRLGs [RFC8800]
- msn: Minimize the number of Shared Nodes [RFC8800]
Introspection Commands
----------------------
.. index:: show sr-te policy [detail]
.. clicmd:: show sr-te policy [detail]
Display the segment routing policies.
.. code-block:: frr
router# show sr-te policy
Endpoint Color Name BSID Status
------------------------------------------
1.1.1.1 1 default 4000 Active
.. code-block:: frr
router# show sr-te policy detail
Endpoint: 1.1.1.1 Color: 1 Name: LOW_DELAY BSID: 4000 Status: Active
Preference: 100 Name: cand1 Type: explicit Segment-List: sl1 Protocol-Origin: Local
* Preference: 200 Name: cand1 Type: dynamic Segment-List: 32453452 Protocol-Origin: PCEP
The asterisk (*) marks the best, e.g. active, candidate path. Note that for segment-lists which are
retrieved via PCEP a random number based name is generated.
Usage with BGP route-maps
=========================
It is possible to steer traffic 'into' a segment routing policy for routes
learned through BGP using route-maps:
.. code-block:: frr
route-map SET_SR_POLICY permit 10
set sr-te color 1
!
router bgp 1
bgp router-id 2.2.2.2
neighbor 1.1.1.1 remote-as 1
neighbor 1.1.1.1 update-source lo
!
address-family ipv4 unicast
neighbor 1.1.1.1 next-hop-self
neighbor 1.1.1.1 route-map SET_SR_POLICY in
redistribute static
exit-address-family
!
!
In this case, the SR Policy with color `1` and endpoint `1.1.1.1` is selected.

View File

@ -27,6 +27,7 @@ user_RSTFILES = \
doc/user/ospf_fundamentals.rst \
doc/user/overview.rst \
doc/user/packet-dumps.rst \
doc/user/pathd.rst \
doc/user/pim.rst \
doc/user/ripd.rst \
doc/user/pbr.rst \

View File

@ -863,6 +863,18 @@ enum node_type node_parent(enum node_type node)
case BFD_PROFILE_NODE:
ret = BFD_NODE;
break;
case SR_TRAFFIC_ENG_NODE:
ret = SEGMENT_ROUTING_NODE;
break;
case SR_SEGMENT_LIST_NODE:
ret = SR_TRAFFIC_ENG_NODE;
break;
case SR_POLICY_NODE:
ret = SR_TRAFFIC_ENG_NODE;
break;
case SR_CANDIDATE_DYN_NODE:
ret = SR_POLICY_NODE;
break;
default:
ret = CONFIG_NODE;
break;

View File

@ -145,6 +145,11 @@ enum node_type {
PROTOCOL_NODE, /* protocol filtering node */
MPLS_NODE, /* MPLS config node */
PW_NODE, /* Pseudowire config node */
SEGMENT_ROUTING_NODE, /* Segment routing root node */
SR_TRAFFIC_ENG_NODE, /* SR Traffic Engineering node */
SR_SEGMENT_LIST_NODE, /* SR segment list config node */
SR_POLICY_NODE, /* SR policy config node */
SR_CANDIDATE_DYN_NODE, /* SR dynamic candidate path config node */
VTY_NODE, /* Vty node. */
FPM_NODE, /* Dataplane FPM node. */
LINK_PARAMS_NODE, /* Link-parameters node */

View File

@ -132,6 +132,8 @@ struct ferr {
#define VTYSH_FRR_END 0x0FFFFFFF
#define WATCHFRR_FERR_START 0x10000001
#define WATCHFRR_FERR_END 0x10FFFFFF
#define PATH_FERR_START 0x11000001
#define PATH_FERR_END 0x11FFFFFF
#define ZEBRA_FERR_START 0xF1000001
#define ZEBRA_FERR_END 0xF1FFFFFF
#define END_FERR 0xFFFFFFFF

View File

@ -92,6 +92,7 @@ static const char *const frr_native_modules[] = {
"frr-isisd",
"frr-vrrpd",
"frr-zebra",
"frr-pathd",
};
/* clang-format on */

2
pathd/.gitignore vendored Normal file
View File

@ -0,0 +1,2 @@
libpath.a
pathd

10
pathd/Makefile Normal file
View File

@ -0,0 +1,10 @@
all: ALWAYS
@$(MAKE) -s -C .. pathd/pathd
%: ALWAYS
@$(MAKE) -s -C .. pathd/$@
Makefile:
#nothing
ALWAYS:
.PHONY: ALWAYS makefiles
.SUFFIXES:

1108
pathd/path_cli.c Normal file

File diff suppressed because it is too large Load Diff

121
pathd/path_debug.c Normal file
View File

@ -0,0 +1,121 @@
/*
* Copyright (C) 2020 NetDEF, Inc.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
* Software Foundation; either version 2 of the License, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; see the file COPYING; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <string.h>
#include <stdbool.h>
#include <time.h>
#include <libyang/libyang.h>
#include "printfrr.h"
#include "ipaddr.h"
#include "pathd/path_debug.h"
THREAD_DATA char _debug_buff[DEBUG_BUFF_SIZE];
/**
* Gives the string representation of an srte_protocol_origin enum value.
*
* @param origin The enum value to convert to string
* @return a constant string representation of the enum value
*/
const char *srte_protocol_origin_name(enum srte_protocol_origin origin)
{
switch (origin) {
case SRTE_ORIGIN_UNDEFINED:
return "UNDEFINED";
case SRTE_ORIGIN_PCEP:
return "PCEP";
case SRTE_ORIGIN_BGP:
return "BGP";
case SRTE_ORIGIN_LOCAL:
return "LOCAL";
default:
return "UNKNOWN";
}
}
/**
* Gives the string representation of an srte_candidate_type enum value.
*
* @param origin The enum value to convert to string
* @return a constant string representation of the enum value
*/
const char *srte_candidate_type_name(enum srte_candidate_type type)
{
switch (type) {
case SRTE_CANDIDATE_TYPE_EXPLICIT:
return "EXPLICIT";
case SRTE_CANDIDATE_TYPE_DYNAMIC:
return "DYNAMIC";
case SRTE_CANDIDATE_TYPE_UNDEFINED:
return "UNDEFINED";
default:
return "UNKNOWN";
}
}
/**
* Gives the string representation of an objfun_type enum value.
*
* @param origin The enum value to convert to string
* @return a constant string representation of the enum value
*/
const char *objfun_type_name(enum objfun_type type)
{
switch (type) {
case OBJFUN_UNDEFINED:
return "UNDEFINED";
case OBJFUN_MCP:
return "MCP";
case OBJFUN_MLP:
return "MLP";
case OBJFUN_MBP:
return "MBP";
case OBJFUN_MBC:
return "MBC";
case OBJFUN_MLL:
return "MLL";
case OBJFUN_MCC:
return "MCC";
case OBJFUN_SPT:
return "SPT";
case OBJFUN_MCT:
return "MCT";
case OBJFUN_MPLP:
return "MPLP";
case OBJFUN_MUP:
return "MUP";
case OBJFUN_MRUP:
return "MRUP";
case OBJFUN_MTD:
return "MTD";
case OBJFUN_MBN:
return "MBN";
case OBJFUN_MCTD:
return "MCTD";
case OBJFUN_MSL:
return "MSL";
case OBJFUN_MSS:
return "MSS";
case OBJFUN_MSN:
return "MSN";
default:
return "UNKNOWN";
}
}

44
pathd/path_debug.h Normal file
View File

@ -0,0 +1,44 @@
/*
* Copyright (C) 2020 NetDEF, Inc.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
* Software Foundation; either version 2 of the License, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; see the file COPYING; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef _PATH_DEBUG_H_
#define _PATH_DEBUG_H_
#include "pathd/pathd.h"
#ifdef __GNUC__
#define THREAD_DATA __thread
#else
#define THREAD_DATA
#endif
#define DEBUG_IDENT_SIZE 4
#define DEBUG_BUFF_SIZE 4096
#define TUP(A, B) ((((uint32_t)(A)) << 16) | ((uint32_t)(B)))
#define PATHD_FORMAT_INIT() _debug_buff[0] = 0
#define PATHD_FORMAT(fmt, ...) \
csnprintfrr(_debug_buff, DEBUG_BUFF_SIZE, fmt, ##__VA_ARGS__)
#define PATHD_FORMAT_FINI() _debug_buff
extern THREAD_DATA char _debug_buff[DEBUG_BUFF_SIZE];
const char *srte_protocol_origin_name(enum srte_protocol_origin origin);
const char *srte_candidate_type_name(enum srte_candidate_type type);
const char *objfun_type_name(enum objfun_type type);
#endif // _PATH_DEBUG_H_

43
pathd/path_errors.c Normal file
View File

@ -0,0 +1,43 @@
/*
* pathd-specific error messages.
* Copyright (C) 2020 NetDEF, Inc.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
* Software Foundation; either version 2 of the License, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; see the file COPYING; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <zebra.h>
#include "lib/ferr.h"
#include "path_errors.h"
/* clang-format off */
static struct log_ref ferr_path_err[] = {
{
.code = END_FERR,
}
};
static struct log_ref ferr_path_warn[] = {
{
.code = END_FERR,
}
};
/* clang-format on */
void path_error_init(void)
{
log_ref_add(ferr_path_err);
log_ref_add(ferr_path_warn);
}

30
pathd/path_errors.h Normal file
View File

@ -0,0 +1,30 @@
/*
* Copyright (C) 2020 NetDEF, Inc.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
* Software Foundation; either version 2 of the License, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; see the file COPYING; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef __PATH_ERRORS_H__
#define __PATH_ERRORS_H__
#include "lib/ferr.h"
enum path_log_refs {
EC_PATH_PCEP_INIT = PATH_FERR_START,
};
extern void path_error_init(void);
#endif

154
pathd/path_main.c Normal file
View File

@ -0,0 +1,154 @@
/*
* Copyright (C) 2020 NetDEF, Inc.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
* Software Foundation; either version 2 of the License, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; see the file COPYING; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <zebra.h>
#include <lib/version.h>
#include "getopt.h"
#include "thread.h"
#include "command.h"
#include "log.h"
#include "memory.h"
#include "privs.h"
#include "sigevent.h"
#include "libfrr.h"
#include "vrf.h"
#include "filter.h"
#include "pathd.h"
#include "path_nb.h"
#include "path_zebra.h"
#include "path_errors.h"
char backup_config_file[256];
zebra_capabilities_t _caps_p[] = {};
struct zebra_privs_t pathd_privs = {
#if defined(FRR_USER) && defined(FRR_GROUP)
.user = FRR_USER,
.group = FRR_GROUP,
#endif
#if defined(VTY_GROUP)
.vty_group = VTY_GROUP,
#endif
.caps_p = _caps_p,
.cap_num_p = array_size(_caps_p),
.cap_num_i = 0};
struct option longopts[] = {{0}};
/* Master of threads. */
struct thread_master *master;
static struct frr_daemon_info pathd_di;
/* SIGHUP handler. */
static void sighup(void)
{
zlog_info("SIGHUP received");
/* Reload config file. */
vty_read_config(NULL, pathd_di.config_file, config_default);
}
/* SIGINT / SIGTERM handler. */
static void sigint(void)
{
zlog_notice("Terminating on signal");
exit(0);
}
/* SIGUSR1 handler. */
static void sigusr1(void)
{
zlog_rotate();
}
struct quagga_signal_t path_signals[] = {
{
.signal = SIGHUP,
.handler = &sighup,
},
{
.signal = SIGUSR1,
.handler = &sigusr1,
},
{
.signal = SIGINT,
.handler = &sigint,
},
{
.signal = SIGTERM,
.handler = &sigint,
},
};
static const struct frr_yang_module_info *pathd_yang_modules[] = {
&frr_filter_info,
&frr_interface_info,
&frr_pathd_info,
};
#define PATH_VTY_PORT 2621
FRR_DAEMON_INFO(pathd, PATH, .vty_port = PATH_VTY_PORT,
.proghelp = "Implementation of PATH.",
.signals = path_signals, .n_signals = array_size(path_signals),
.privs = &pathd_privs, .yang_modules = pathd_yang_modules,
.n_yang_modules = array_size(pathd_yang_modules), )
int main(int argc, char **argv, char **envp)
{
frr_preinit(&pathd_di, argc, argv);
frr_opt_add("", longopts, "");
while (1) {
int opt;
opt = frr_getopt(argc, argv, NULL);
if (opt == EOF)
break;
switch (opt) {
case 0:
break;
default:
frr_help_exit(1);
break;
}
}
master = frr_init();
access_list_init();
path_error_init();
path_zebra_init(master);
path_cli_init();
frr_config_fork();
frr_run(master);
/* Not reached. */
return 0;
}

25
pathd/path_memory.c Normal file
View File

@ -0,0 +1,25 @@
/*
* Copyright (C) 2020 NetDEF, Inc.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
* Software Foundation; either version 2 of the License, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; see the file COPYING; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <zebra.h>
#include <memory.h>
#include "pathd/path_memory.h"
DEFINE_MGROUP(PATHD, "pathd")

26
pathd/path_memory.h Normal file
View File

@ -0,0 +1,26 @@
/*
* Copyright (C) 2020 NetDEF, Inc.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
* Software Foundation; either version 2 of the License, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; see the file COPYING; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef _FRR_PATH_MEMORY_H_
#define _FRR_PATH_MEMORY_H_
#include "memory.h"
DECLARE_MGROUP(PATHD)
#endif /* _FRR_PATH_MEMORY_H_ */

351
pathd/path_nb.c Normal file
View File

@ -0,0 +1,351 @@
/*
* Copyright (C) 2020 NetDEF, Inc.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
* Software Foundation; either version 2 of the License, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; see the file COPYING; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <zebra.h>
#include "northbound.h"
#include "libfrr.h"
#include "pathd/path_nb.h"
static int iter_objfun_cb(const struct lyd_node *dnode, void *arg);
static int dummy_create(struct nb_cb_create_args *args);
static int dummy_modify(struct nb_cb_modify_args *args);
static int dummy_destroy(struct nb_cb_destroy_args *args);
struct of_cb_pref {
uint32_t index;
enum objfun_type type;
struct of_cb_pref *next;
};
struct of_cb_args {
struct of_cb_pref *first;
uint32_t free_slot;
struct of_cb_pref prefs[MAX_OBJFUN_TYPE];
};
/* clang-format off */
const struct frr_yang_module_info frr_pathd_info = {
.name = "frr-pathd",
.nodes = {
{
.xpath = "/frr-pathd:pathd",
.cbs = {
.apply_finish = pathd_apply_finish,
},
.priority = NB_DFLT_PRIORITY + 1
},
{
.xpath = "/frr-pathd:pathd/srte/segment-list",
.cbs = {
.create = pathd_srte_segment_list_create,
.cli_show = cli_show_srte_segment_list,
.destroy = pathd_srte_segment_list_destroy,
.get_next = pathd_srte_segment_list_get_next,
.get_keys = pathd_srte_segment_list_get_keys,
.lookup_entry = pathd_srte_segment_list_lookup_entry,
},
.priority = NB_DFLT_PRIORITY - 1
},
{
.xpath = "/frr-pathd:pathd/srte/segment-list/protocol-origin",
.cbs = {
.modify = pathd_srte_segment_list_protocol_origin_modify,
},
.priority = NB_DFLT_PRIORITY - 1
},
{
.xpath = "/frr-pathd:pathd/srte/segment-list/originator",
.cbs = {
.modify = pathd_srte_segment_list_originator_modify,
},
.priority = NB_DFLT_PRIORITY - 1
},
{
.xpath = "/frr-pathd:pathd/srte/segment-list/segment",
.cbs = {
.create = pathd_srte_segment_list_segment_create,
.cli_show = cli_show_srte_segment_list_segment,
.destroy = pathd_srte_segment_list_segment_destroy,
},
.priority = NB_DFLT_PRIORITY - 1
},
{
.xpath = "/frr-pathd:pathd/srte/segment-list/segment/sid-value",
.cbs = {
.modify = pathd_srte_segment_list_segment_sid_value_modify,
},
.priority = NB_DFLT_PRIORITY - 1
},
{
.xpath = "/frr-pathd:pathd/srte/segment-list/segment/nai",
.cbs = {
.create = dummy_create,
.destroy = pathd_srte_segment_list_segment_nai_destroy,
.apply_finish = pathd_srte_segment_list_segment_nai_apply_finish
},
.priority = NB_DFLT_PRIORITY - 1
},
{
.xpath = "/frr-pathd:pathd/srte/segment-list/segment/nai/type",
.cbs = {.modify = dummy_modify}
},
{
.xpath = "/frr-pathd:pathd/srte/segment-list/segment/nai/local-address",
.cbs = {.modify = dummy_modify}
},
{
.xpath = "/frr-pathd:pathd/srte/segment-list/segment/nai/local-interface",
.cbs = {.modify = dummy_modify, .destroy = dummy_destroy}
},
{
.xpath = "/frr-pathd:pathd/srte/segment-list/segment/nai/remote-address",
.cbs = {.modify = dummy_modify, .destroy = dummy_destroy}
},
{
.xpath = "/frr-pathd:pathd/srte/segment-list/segment/nai/remote-interface",
.cbs = {.modify = dummy_modify, .destroy = dummy_destroy}
},
{
.xpath = "/frr-pathd:pathd/srte/policy",
.cbs = {
.create = pathd_srte_policy_create,
.cli_show = cli_show_srte_policy,
.destroy = pathd_srte_policy_destroy,
.get_next = pathd_srte_policy_get_next,
.get_keys = pathd_srte_policy_get_keys,
.lookup_entry = pathd_srte_policy_lookup_entry,
}
},
{
.xpath = "/frr-pathd:pathd/srte/policy/name",
.cbs = {
.modify = pathd_srte_policy_name_modify,
.cli_show = cli_show_srte_policy_name,
.destroy = pathd_srte_policy_name_destroy,
}
},
{
.xpath = "/frr-pathd:pathd/srte/policy/binding-sid",
.cbs = {
.modify = pathd_srte_policy_binding_sid_modify,
.cli_show = cli_show_srte_policy_binding_sid,
.destroy = pathd_srte_policy_binding_sid_destroy,
}
},
{
.xpath = "/frr-pathd:pathd/srte/policy/is-operational",
.cbs = {
.get_elem = pathd_srte_policy_is_operational_get_elem
}
},
{
.xpath = "/frr-pathd:pathd/srte/policy/candidate-path",
.cbs = {
.create = pathd_srte_policy_candidate_path_create,
.cli_show = cli_show_srte_policy_candidate_path,
.destroy = pathd_srte_policy_candidate_path_destroy,
.get_next = pathd_srte_policy_candidate_path_get_next,
.get_keys = pathd_srte_policy_candidate_path_get_keys,
.lookup_entry = pathd_srte_policy_candidate_path_lookup_entry,
}
},
{
.xpath = "/frr-pathd:pathd/srte/policy/candidate-path/name",
.cbs = {
.modify = pathd_srte_policy_candidate_path_name_modify,
}
},
{
.xpath = "/frr-pathd:pathd/srte/policy/candidate-path/is-best-candidate-path",
.cbs = {
.get_elem = pathd_srte_policy_candidate_path_is_best_candidate_path_get_elem,
}
},
{
.xpath = "/frr-pathd:pathd/srte/policy/candidate-path/protocol-origin",
.cbs = {
.modify = pathd_srte_policy_candidate_path_protocol_origin_modify,
}
},
{
.xpath = "/frr-pathd:pathd/srte/policy/candidate-path/originator",
.cbs = {
.modify = pathd_srte_policy_candidate_path_originator_modify,
}
},
{
.xpath = "/frr-pathd:pathd/srte/policy/candidate-path/discriminator",
.cbs = {
.get_elem = pathd_srte_policy_candidate_path_discriminator_get_elem,
}
},
{
.xpath = "/frr-pathd:pathd/srte/policy/candidate-path/type",
.cbs = {
.modify = pathd_srte_policy_candidate_path_type_modify,
}
},
{
.xpath = "/frr-pathd:pathd/srte/policy/candidate-path/segment-list-name",
.cbs = {
.destroy = pathd_srte_policy_candidate_path_segment_list_name_destroy,
.modify = pathd_srte_policy_candidate_path_segment_list_name_modify,
}
},
{
.xpath = "/frr-pathd:pathd/srte/policy/candidate-path/constraints/bandwidth",
.cbs = {
.create = dummy_create,
.destroy = pathd_srte_policy_candidate_path_bandwidth_destroy,
.apply_finish = pathd_srte_policy_candidate_path_bandwidth_apply_finish
}
},
{
.xpath = "/frr-pathd:pathd/srte/policy/candidate-path/constraints/bandwidth/required",
.cbs = {.modify = dummy_modify}
},
{
.xpath = "/frr-pathd:pathd/srte/policy/candidate-path/constraints/bandwidth/value",
.cbs = {.modify = dummy_modify}
},
{
.xpath = "/frr-pathd:pathd/srte/policy/candidate-path/constraints/affinity/exclude-any",
.cbs = {
.modify = pathd_srte_policy_candidate_path_exclude_any_modify,
.destroy = pathd_srte_policy_candidate_path_exclude_any_destroy,
}
},
{
.xpath = "/frr-pathd:pathd/srte/policy/candidate-path/constraints/affinity/include-any",
.cbs = {
.modify = pathd_srte_policy_candidate_path_include_any_modify,
.destroy = pathd_srte_policy_candidate_path_include_any_destroy,
}
},
{
.xpath = "/frr-pathd:pathd/srte/policy/candidate-path/constraints/affinity/include-all",
.cbs = {
.modify = pathd_srte_policy_candidate_path_include_all_modify,
.destroy = pathd_srte_policy_candidate_path_include_all_destroy,
}
},
{
.xpath = "/frr-pathd:pathd/srte/policy/candidate-path/constraints/metrics",
.cbs = {
.create = dummy_create,
.destroy = pathd_srte_policy_candidate_path_metrics_destroy,
.apply_finish = pathd_srte_policy_candidate_path_metrics_apply_finish
}
},
{
.xpath = "/frr-pathd:pathd/srte/policy/candidate-path/constraints/metrics/value",
.cbs = {.modify = dummy_modify}
},
{
.xpath = "/frr-pathd:pathd/srte/policy/candidate-path/constraints/metrics/required",
.cbs = {.modify = dummy_modify}
},
{
.xpath = "/frr-pathd:pathd/srte/policy/candidate-path/constraints/metrics/is-bound",
.cbs = {.modify = dummy_modify, .destroy = dummy_destroy}
},
{
.xpath = "/frr-pathd:pathd/srte/policy/candidate-path/constraints/metrics/is-computed",
.cbs = {.modify = dummy_modify, .destroy = dummy_destroy}
},
{
.xpath = "/frr-pathd:pathd/srte/policy/candidate-path/constraints/objective-function",
.cbs = {
.create = dummy_create,
.destroy = pathd_srte_policy_candidate_path_objfun_destroy,
.apply_finish = pathd_srte_policy_candidate_path_objfun_apply_finish
}
},
{
.xpath = "/frr-pathd:pathd/srte/policy/candidate-path/constraints/objective-function/required",
.cbs = {.modify = dummy_modify}
},
{
.xpath = "/frr-pathd:pathd/srte/policy/candidate-path/constraints/objective-function/type",
.cbs = {.modify = dummy_modify}
},
{
.xpath = NULL,
},
}
};
void iter_objfun_prefs(const struct lyd_node *dnode, const char* path,
of_pref_cp_t fun, void *arg)
{
struct of_cb_args args = {0};
struct of_cb_pref *p;
yang_dnode_iterate(iter_objfun_cb, &args, dnode, path);
for (p = args.first; p != NULL; p = p->next)
fun(p->type, arg);
}
int iter_objfun_cb(const struct lyd_node *dnode, void *arg)
{
struct of_cb_args *of_arg = arg;
struct of_cb_pref *pref;
struct of_cb_pref **p;
if (of_arg->free_slot >= MAX_OBJFUN_TYPE)
return YANG_ITER_STOP;
pref = &of_arg->prefs[of_arg->free_slot++];
pref->index = yang_dnode_get_uint32(dnode, "./index");
pref->type = yang_dnode_get_enum(dnode, "./type");
/* Simplistic insertion sort */
p = &of_arg->first;
while (true) {
if (*p == NULL) {
*p = pref;
break;
}
if ((*p)->index >= pref->index) {
pref->next = *p;
*p = pref;
break;
}
p = &(*p)->next;
}
return YANG_ITER_CONTINUE;
}
int dummy_create(struct nb_cb_create_args *args)
{
return NB_OK;
}
int dummy_modify(struct nb_cb_modify_args *args)
{
return NB_OK;
}
int dummy_destroy(struct nb_cb_destroy_args *args)
{
return NB_OK;
}

130
pathd/path_nb.h Normal file
View File

@ -0,0 +1,130 @@
/*
* Copyright (C) 2020 NetDEF, Inc.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
* Software Foundation; either version 2 of the License, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; see the file COPYING; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef _FRR_PATH_NB_H_
#define _FRR_PATH_NB_H_
#include "pathd/pathd.h"
extern const struct frr_yang_module_info frr_pathd_info;
/* Mandatory callbacks. */
int pathd_srte_segment_list_create(struct nb_cb_create_args *args);
int pathd_srte_segment_list_destroy(struct nb_cb_destroy_args *args);
const void *pathd_srte_segment_list_get_next(struct nb_cb_get_next_args *args);
int pathd_srte_segment_list_get_keys(struct nb_cb_get_keys_args *args);
const void *
pathd_srte_segment_list_lookup_entry(struct nb_cb_lookup_entry_args *args);
int pathd_srte_segment_list_segment_create(struct nb_cb_create_args *args);
int pathd_srte_segment_list_segment_destroy(struct nb_cb_destroy_args *args);
int pathd_srte_segment_list_protocol_origin_modify(
struct nb_cb_modify_args *args);
int pathd_srte_segment_list_originator_modify(struct nb_cb_modify_args *args);
int pathd_srte_segment_list_segment_sid_value_modify(
struct nb_cb_modify_args *args);
int pathd_srte_segment_list_segment_nai_destroy(
struct nb_cb_destroy_args *args);
void pathd_srte_segment_list_segment_nai_apply_finish(
struct nb_cb_apply_finish_args *args);
int pathd_srte_policy_create(struct nb_cb_create_args *args);
int pathd_srte_policy_destroy(struct nb_cb_destroy_args *args);
const void *pathd_srte_policy_get_next(struct nb_cb_get_next_args *args);
int pathd_srte_policy_get_keys(struct nb_cb_get_keys_args *args);
const void *
pathd_srte_policy_lookup_entry(struct nb_cb_lookup_entry_args *args);
int pathd_srte_policy_name_modify(struct nb_cb_modify_args *args);
int pathd_srte_policy_name_destroy(struct nb_cb_destroy_args *args);
int pathd_srte_policy_binding_sid_modify(struct nb_cb_modify_args *args);
int pathd_srte_policy_binding_sid_destroy(struct nb_cb_destroy_args *args);
struct yang_data *
pathd_srte_policy_is_operational_get_elem(struct nb_cb_get_elem_args *args);
int pathd_srte_policy_candidate_path_create(struct nb_cb_create_args *args);
int pathd_srte_policy_candidate_path_destroy(struct nb_cb_destroy_args *args);
int pathd_srte_policy_candidate_path_name_modify(
struct nb_cb_modify_args *args);
const void *
pathd_srte_policy_candidate_path_get_next(struct nb_cb_get_next_args *args);
int pathd_srte_policy_candidate_path_get_keys(struct nb_cb_get_keys_args *args);
const void *pathd_srte_policy_candidate_path_lookup_entry(
struct nb_cb_lookup_entry_args *args);
void pathd_srte_policy_candidate_path_bandwidth_apply_finish(
struct nb_cb_apply_finish_args *args);
int pathd_srte_policy_candidate_path_bandwidth_destroy(
struct nb_cb_destroy_args *args);
int pathd_srte_policy_candidate_path_exclude_any_modify(
struct nb_cb_modify_args *args);
int pathd_srte_policy_candidate_path_exclude_any_destroy(
struct nb_cb_destroy_args *args);
int pathd_srte_policy_candidate_path_include_any_modify(
struct nb_cb_modify_args *args);
int pathd_srte_policy_candidate_path_include_any_destroy(
struct nb_cb_destroy_args *args);
int pathd_srte_policy_candidate_path_include_all_modify(
struct nb_cb_modify_args *args);
int pathd_srte_policy_candidate_path_include_all_destroy(
struct nb_cb_destroy_args *args);
int pathd_srte_policy_candidate_path_metrics_destroy(
struct nb_cb_destroy_args *args);
void pathd_srte_policy_candidate_path_metrics_apply_finish(
struct nb_cb_apply_finish_args *args);
int pathd_srte_policy_candidate_path_objfun_destroy(
struct nb_cb_destroy_args *args);
void pathd_srte_policy_candidate_path_objfun_apply_finish(
struct nb_cb_apply_finish_args *args);
struct yang_data *
pathd_srte_policy_candidate_path_is_best_candidate_path_get_elem(
struct nb_cb_get_elem_args *args);
int pathd_srte_policy_candidate_path_protocol_origin_modify(
struct nb_cb_modify_args *args);
int pathd_srte_policy_candidate_path_originator_modify(
struct nb_cb_modify_args *args);
struct yang_data *pathd_srte_policy_candidate_path_discriminator_get_elem(
struct nb_cb_get_elem_args *args);
int pathd_srte_policy_candidate_path_type_modify(
struct nb_cb_modify_args *args);
int pathd_srte_policy_candidate_path_segment_list_name_modify(
struct nb_cb_modify_args *args);
int pathd_srte_policy_candidate_path_segment_list_name_destroy(
struct nb_cb_destroy_args *args);
/* Optional 'apply_finish' callbacks. */
void pathd_apply_finish(struct nb_cb_apply_finish_args *args);
/* Optional 'cli_show' callbacks. */
void cli_show_srte_segment_list(struct vty *vty, struct lyd_node *dnode,
bool show_defaults);
void cli_show_srte_segment_list_segment(struct vty *vty, struct lyd_node *dnode,
bool show_defaults);
void cli_show_srte_policy(struct vty *vty, struct lyd_node *dnode,
bool show_defaults);
void cli_show_srte_policy_name(struct vty *vty, struct lyd_node *dnode,
bool show_defaults);
void cli_show_srte_policy_binding_sid(struct vty *vty, struct lyd_node *dnode,
bool show_defaults);
void cli_show_srte_policy_candidate_path(struct vty *vty,
struct lyd_node *dnode,
bool show_defaults);
/* Utility functions */
typedef void (*of_pref_cp_t)(enum objfun_type type, void *arg);
void iter_objfun_prefs(const struct lyd_node *dnode, const char *path,
of_pref_cp_t fun, void *arg);
#endif /* _FRR_PATH_NB_H_ */

731
pathd/path_nb_config.c Normal file
View File

@ -0,0 +1,731 @@
/*
* Copyright (C) 2020 NetDEF, Inc.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
* Software Foundation; either version 2 of the License, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; see the file COPYING; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <zebra.h>
#include <lib_errors.h>
#include "northbound.h"
#include "libfrr.h"
#include "pathd/path_zebra.h"
#include "pathd/path_nb.h"
/*
* XPath: /frr-pathd:pathd
*/
void pathd_apply_finish(struct nb_cb_apply_finish_args *args)
{
srte_apply_changes();
}
/*
* XPath: /frr-pathd:pathd/srte/segment-list
*/
int pathd_srte_segment_list_create(struct nb_cb_create_args *args)
{
struct srte_segment_list *segment_list;
const char *name;
if (args->event != NB_EV_APPLY)
return NB_OK;
name = yang_dnode_get_string(args->dnode, "./name");
segment_list = srte_segment_list_add(name);
nb_running_set_entry(args->dnode, segment_list);
SET_FLAG(segment_list->flags, F_SEGMENT_LIST_NEW);
return NB_OK;
}
int pathd_srte_segment_list_destroy(struct nb_cb_destroy_args *args)
{
struct srte_segment_list *segment_list;
if (args->event != NB_EV_APPLY)
return NB_OK;
segment_list = nb_running_unset_entry(args->dnode);
SET_FLAG(segment_list->flags, F_SEGMENT_LIST_DELETED);
return NB_OK;
}
/*
* XPath: /frr-pathd:pathd/srte/segment-list/protocol-origin
*/
int pathd_srte_segment_list_protocol_origin_modify(
struct nb_cb_modify_args *args)
{
struct srte_segment_list *segment_list;
if (args->event != NB_EV_APPLY)
return NB_OK;
segment_list = nb_running_get_entry(args->dnode, NULL, true);
segment_list->protocol_origin = yang_dnode_get_enum(args->dnode, NULL);
SET_FLAG(segment_list->flags, F_SEGMENT_LIST_MODIFIED);
return NB_OK;
}
/*
* XPath: /frr-pathd:pathd/srte/segment-list/originator
*/
int pathd_srte_segment_list_originator_modify(struct nb_cb_modify_args *args)
{
struct srte_segment_list *segment_list;
const char *originator;
if (args->event != NB_EV_APPLY)
return NB_OK;
segment_list = nb_running_get_entry(args->dnode, NULL, true);
originator = yang_dnode_get_string(args->dnode, NULL);
strlcpy(segment_list->originator, originator,
sizeof(segment_list->originator));
SET_FLAG(segment_list->flags, F_SEGMENT_LIST_MODIFIED);
return NB_OK;
}
/*
* XPath: /frr-pathd:pathd/srte/segment-list/segment
*/
int pathd_srte_segment_list_segment_create(struct nb_cb_create_args *args)
{
struct srte_segment_list *segment_list;
struct srte_segment_entry *segment;
uint32_t index;
if (args->event != NB_EV_APPLY)
return NB_OK;
segment_list = nb_running_get_entry(args->dnode, NULL, true);
index = yang_dnode_get_uint32(args->dnode, "./index");
segment = srte_segment_entry_add(segment_list, index);
nb_running_set_entry(args->dnode, segment);
SET_FLAG(segment_list->flags, F_SEGMENT_LIST_MODIFIED);
return NB_OK;
}
int pathd_srte_segment_list_segment_destroy(struct nb_cb_destroy_args *args)
{
struct srte_segment_entry *segment;
if (args->event != NB_EV_APPLY)
return NB_OK;
segment = nb_running_unset_entry(args->dnode);
SET_FLAG(segment->segment_list->flags, F_SEGMENT_LIST_MODIFIED);
srte_segment_entry_del(segment);
return NB_OK;
}
/*
* XPath: /frr-pathd:pathd/srte/segment-list/segment/sid-value
*/
int pathd_srte_segment_list_segment_sid_value_modify(
struct nb_cb_modify_args *args)
{
mpls_label_t sid_value;
struct srte_segment_entry *segment;
if (args->event != NB_EV_APPLY)
return NB_OK;
segment = nb_running_get_entry(args->dnode, NULL, true);
sid_value = yang_dnode_get_uint32(args->dnode, NULL);
segment->sid_value = sid_value;
SET_FLAG(segment->segment_list->flags, F_SEGMENT_LIST_MODIFIED);
return NB_OK;
}
int pathd_srte_segment_list_segment_nai_destroy(struct nb_cb_destroy_args *args)
{
struct srte_segment_entry *segment;
if (args->event != NB_EV_APPLY)
return NB_OK;
segment = nb_running_get_entry(args->dnode, NULL, true);
segment->nai_type = SRTE_SEGMENT_NAI_TYPE_NONE;
segment->nai_local_addr.ipa_type = IPADDR_NONE;
segment->nai_local_iface = 0;
segment->nai_remote_addr.ipa_type = IPADDR_NONE;
segment->nai_remote_iface = 0;
return NB_OK;
}
void pathd_srte_segment_list_segment_nai_apply_finish(
struct nb_cb_apply_finish_args *args)
{
struct srte_segment_entry *segment;
enum srte_segment_nai_type type;
struct ipaddr local_addr, remote_addr;
uint32_t local_iface = 0, remote_iface = 0;
segment = nb_running_get_entry(args->dnode, NULL, true);
type = yang_dnode_get_enum(args->dnode, "./type");
yang_dnode_get_ip(&local_addr, args->dnode, "./local-address");
switch (type) {
case SRTE_SEGMENT_NAI_TYPE_IPV4_NODE:
case SRTE_SEGMENT_NAI_TYPE_IPV6_NODE:
break;
case SRTE_SEGMENT_NAI_TYPE_IPV4_ADJACENCY:
case SRTE_SEGMENT_NAI_TYPE_IPV6_ADJACENCY:
yang_dnode_get_ip(&remote_addr, args->dnode,
"./remote-address");
break;
case SRTE_SEGMENT_NAI_TYPE_IPV4_UNNUMBERED_ADJACENCY:
yang_dnode_get_ip(&remote_addr, args->dnode,
"./remote-address");
local_iface =
yang_dnode_get_uint32(args->dnode, "./local-interface");
remote_iface = yang_dnode_get_uint32(args->dnode,
"./remote-interface");
break;
default:
break;
}
srte_segment_entry_set_nai(segment, type, &local_addr, local_iface,
&remote_addr, remote_iface);
}
/*
* XPath: /frr-pathd:pathd/srte/policy
*/
int pathd_srte_policy_create(struct nb_cb_create_args *args)
{
struct srte_policy *policy;
uint32_t color;
struct ipaddr endpoint;
if (args->event != NB_EV_APPLY)
return NB_OK;
color = yang_dnode_get_uint32(args->dnode, "./color");
yang_dnode_get_ip(&endpoint, args->dnode, "./endpoint");
policy = srte_policy_add(color, &endpoint);
nb_running_set_entry(args->dnode, policy);
SET_FLAG(policy->flags, F_POLICY_NEW);
return NB_OK;
}
int pathd_srte_policy_destroy(struct nb_cb_destroy_args *args)
{
struct srte_policy *policy;
if (args->event != NB_EV_APPLY)
return NB_OK;
policy = nb_running_unset_entry(args->dnode);
SET_FLAG(policy->flags, F_POLICY_DELETED);
return NB_OK;
}
/*
* XPath: /frr-pathd:pathd/srte/policy/name
*/
int pathd_srte_policy_name_modify(struct nb_cb_modify_args *args)
{
struct srte_policy *policy;
const char *name;
if (args->event != NB_EV_APPLY && args->event != NB_EV_VALIDATE)
return NB_OK;
policy = nb_running_get_entry(args->dnode, NULL, true);
if (args->event == NB_EV_VALIDATE) {
/* the policy name is fixed after setting it once */
if (strlen(policy->name) > 0) {
flog_warn(EC_LIB_NB_CB_CONFIG_VALIDATE,
"The SR Policy name is fixed!");
return NB_ERR_RESOURCE;
} else
return NB_OK;
}
name = yang_dnode_get_string(args->dnode, NULL);
strlcpy(policy->name, name, sizeof(policy->name));
SET_FLAG(policy->flags, F_POLICY_MODIFIED);
return NB_OK;
}
int pathd_srte_policy_name_destroy(struct nb_cb_destroy_args *args)
{
struct srte_policy *policy;
if (args->event != NB_EV_APPLY)
return NB_OK;
policy = nb_running_get_entry(args->dnode, NULL, true);
policy->name[0] = '\0';
SET_FLAG(policy->flags, F_POLICY_MODIFIED);
return NB_OK;
}
/*
* XPath: /frr-pathd:pathd/srte/policy/binding-sid
*/
int pathd_srte_policy_binding_sid_modify(struct nb_cb_modify_args *args)
{
struct srte_policy *policy;
mpls_label_t binding_sid;
policy = nb_running_get_entry(args->dnode, NULL, true);
binding_sid = yang_dnode_get_uint32(args->dnode, NULL);
switch (args->event) {
case NB_EV_VALIDATE:
break;
case NB_EV_PREPARE:
if (path_zebra_request_label(binding_sid) < 0)
return NB_ERR_RESOURCE;
break;
case NB_EV_ABORT:
break;
case NB_EV_APPLY:
srte_policy_update_binding_sid(policy, binding_sid);
SET_FLAG(policy->flags, F_POLICY_MODIFIED);
break;
}
return NB_OK;
}
int pathd_srte_policy_binding_sid_destroy(struct nb_cb_destroy_args *args)
{
struct srte_policy *policy;
if (args->event != NB_EV_APPLY)
return NB_OK;
policy = nb_running_get_entry(args->dnode, NULL, true);
srte_policy_update_binding_sid(policy, MPLS_LABEL_NONE);
SET_FLAG(policy->flags, F_POLICY_MODIFIED);
return NB_OK;
}
/*
* XPath: /frr-pathd:pathd/srte/policy/candidate-path
*/
int pathd_srte_policy_candidate_path_create(struct nb_cb_create_args *args)
{
struct srte_policy *policy;
struct srte_candidate *candidate;
uint32_t preference;
if (args->event != NB_EV_APPLY)
return NB_OK;
policy = nb_running_get_entry(args->dnode, NULL, true);
preference = yang_dnode_get_uint32(args->dnode, "./preference");
candidate = srte_candidate_add(policy, preference);
nb_running_set_entry(args->dnode, candidate);
SET_FLAG(candidate->flags, F_CANDIDATE_NEW);
return NB_OK;
}
int pathd_srte_policy_candidate_path_destroy(struct nb_cb_destroy_args *args)
{
struct srte_candidate *candidate;
if (args->event != NB_EV_APPLY)
return NB_OK;
candidate = nb_running_unset_entry(args->dnode);
SET_FLAG(candidate->flags, F_CANDIDATE_DELETED);
return NB_OK;
}
/*
* XPath: /frr-pathd:pathd/srte/policy/candidate-path/name
*/
int pathd_srte_policy_candidate_path_name_modify(struct nb_cb_modify_args *args)
{
struct srte_candidate *candidate;
const char *name;
char xpath[XPATH_MAXLEN];
char xpath_buf[XPATH_MAXLEN - 3];
if (args->event != NB_EV_APPLY && args->event != NB_EV_VALIDATE)
return NB_OK;
/* the candidate name is fixed after setting it once, this is checked
* here */
if (args->event == NB_EV_VALIDATE) {
/* first get the precise path to the candidate path */
yang_dnode_get_path(args->dnode, xpath_buf, sizeof(xpath_buf));
snprintf(xpath, sizeof(xpath), "%s%s", xpath_buf, "/..");
candidate = nb_running_get_entry_non_rec(NULL, xpath, false);
/* then check if it exists and if the name was provided */
if (candidate && strlen(candidate->name) > 0) {
flog_warn(EC_LIB_NB_CB_CONFIG_VALIDATE,
"The candidate name is fixed!");
return NB_ERR_RESOURCE;
} else
return NB_OK;
}
candidate = nb_running_get_entry(args->dnode, NULL, true);
name = yang_dnode_get_string(args->dnode, NULL);
strlcpy(candidate->name, name, sizeof(candidate->name));
SET_FLAG(candidate->flags, F_CANDIDATE_MODIFIED);
return NB_OK;
}
static int affinity_filter_modify(struct nb_cb_modify_args *args,
enum affinity_filter_type type)
{
uint32_t filter;
struct srte_candidate *candidate;
if (args->event != NB_EV_APPLY)
return NB_OK;
assert(args->context != NULL);
candidate = nb_running_get_entry(args->dnode, NULL, true);
filter = yang_dnode_get_uint32(args->dnode, NULL);
srte_candidate_set_affinity_filter(candidate, type, filter);
return NB_OK;
}
static int affinity_filter_destroy(struct nb_cb_destroy_args *args,
enum affinity_filter_type type)
{
struct srte_candidate *candidate;
if (args->event != NB_EV_APPLY)
return NB_OK;
assert(args->context != NULL);
candidate = nb_running_get_entry(args->dnode, NULL, true);
srte_candidate_unset_affinity_filter(candidate, type);
return NB_OK;
}
/*
* XPath:
* /frr-pathd:pathd/srte/policy/candidate-path/constraints/affinity/exclude-any
*/
int pathd_srte_policy_candidate_path_exclude_any_modify(
struct nb_cb_modify_args *args)
{
return affinity_filter_modify(args, AFFINITY_FILTER_EXCLUDE_ANY);
}
int pathd_srte_policy_candidate_path_exclude_any_destroy(
struct nb_cb_destroy_args *args)
{
return affinity_filter_destroy(args, AFFINITY_FILTER_EXCLUDE_ANY);
}
/*
* XPath:
* /frr-pathd:pathd/srte/policy/candidate-path/constraints/affinity/include-any
*/
int pathd_srte_policy_candidate_path_include_any_modify(
struct nb_cb_modify_args *args)
{
return affinity_filter_modify(args, AFFINITY_FILTER_INCLUDE_ANY);
}
int pathd_srte_policy_candidate_path_include_any_destroy(
struct nb_cb_destroy_args *args)
{
return affinity_filter_destroy(args, AFFINITY_FILTER_INCLUDE_ANY);
}
/*
* XPath:
* /frr-pathd:pathd/srte/policy/candidate-path/constraints/affinity/include-all
*/
int pathd_srte_policy_candidate_path_include_all_modify(
struct nb_cb_modify_args *args)
{
return affinity_filter_modify(args, AFFINITY_FILTER_INCLUDE_ALL);
}
int pathd_srte_policy_candidate_path_include_all_destroy(
struct nb_cb_destroy_args *args)
{
return affinity_filter_destroy(args, AFFINITY_FILTER_INCLUDE_ALL);
}
/*
* XPath: /frr-pathd:pathd/srte/policy/candidate-path/constraints/metrics
*/
int pathd_srte_policy_candidate_path_metrics_destroy(
struct nb_cb_destroy_args *args)
{
struct srte_candidate *candidate;
enum srte_candidate_metric_type type;
if (args->event != NB_EV_APPLY)
return NB_OK;
assert(args->context != NULL);
candidate = nb_running_get_entry(args->dnode, NULL, true);
type = yang_dnode_get_enum(args->dnode, "./type");
srte_candidate_unset_metric(candidate, type);
return NB_OK;
}
void pathd_srte_policy_candidate_path_metrics_apply_finish(
struct nb_cb_apply_finish_args *args)
{
struct srte_candidate *candidate;
enum srte_candidate_metric_type type;
float value;
bool required, is_bound = false, is_computed = false;
assert(args->context != NULL);
candidate = nb_running_get_entry(args->dnode, NULL, true);
type = yang_dnode_get_enum(args->dnode, "./type");
value = (float)yang_dnode_get_dec64(args->dnode, "./value");
required = yang_dnode_get_bool(args->dnode, "./required");
if (yang_dnode_exists(args->dnode, "./is-bound"))
is_bound = yang_dnode_get_bool(args->dnode, "./is-bound");
if (yang_dnode_exists(args->dnode, "./is-computed"))
is_computed = yang_dnode_get_bool(args->dnode, "./is-computed");
srte_candidate_set_metric(candidate, type, value, required, is_bound,
is_computed);
}
/*
* XPath:
* /frr-pathd:pathd/srte/policy/candidate-path/constraints/objective-function
*/
int pathd_srte_policy_candidate_path_objfun_destroy(
struct nb_cb_destroy_args *args)
{
struct srte_candidate *candidate;
if (args->event != NB_EV_APPLY)
return NB_OK;
assert(args->context != NULL);
candidate = nb_running_get_entry(args->dnode, NULL, true);
srte_candidate_unset_objfun(candidate);
return NB_OK;
}
void pathd_srte_policy_candidate_path_objfun_apply_finish(
struct nb_cb_apply_finish_args *args)
{
struct srte_candidate *candidate;
enum objfun_type type;
bool required;
candidate = nb_running_get_entry(args->dnode, NULL, true);
required = yang_dnode_get_bool(args->dnode, "./required");
type = yang_dnode_get_enum(args->dnode, "./type");
srte_candidate_set_objfun(candidate, required, type);
}
/*
* XPath: /frr-pathd:pathd/srte/policy/candidate-path/protocol-origin
*/
int pathd_srte_policy_candidate_path_protocol_origin_modify(
struct nb_cb_modify_args *args)
{
struct srte_candidate *candidate;
enum srte_protocol_origin protocol_origin;
if (args->event != NB_EV_APPLY)
return NB_OK;
candidate = nb_running_get_entry(args->dnode, NULL, true);
protocol_origin = yang_dnode_get_enum(args->dnode, NULL);
candidate->protocol_origin = protocol_origin;
candidate->lsp->protocol_origin = protocol_origin;
SET_FLAG(candidate->flags, F_CANDIDATE_MODIFIED);
return NB_OK;
}
/*
* XPath: /frr-pathd:pathd/srte/policy/candidate-path/originator
*/
int pathd_srte_policy_candidate_path_originator_modify(
struct nb_cb_modify_args *args)
{
struct srte_candidate *candidate;
const char *originator;
if (args->event != NB_EV_APPLY)
return NB_OK;
candidate = nb_running_get_entry(args->dnode, NULL, true);
originator = yang_dnode_get_string(args->dnode, NULL);
strlcpy(candidate->originator, originator,
sizeof(candidate->originator));
strlcpy(candidate->lsp->originator, originator,
sizeof(candidate->lsp->originator));
SET_FLAG(candidate->flags, F_CANDIDATE_MODIFIED);
return NB_OK;
}
/*
* XPath: /frr-pathd:pathd/srte/policy/candidate-path/type
*/
int pathd_srte_policy_candidate_path_type_modify(struct nb_cb_modify_args *args)
{
struct srte_candidate *candidate;
enum srte_candidate_type type;
char xpath[XPATH_MAXLEN];
char xpath_buf[XPATH_MAXLEN - 3];
if (args->event != NB_EV_APPLY && args->event != NB_EV_VALIDATE)
return NB_OK;
/* the candidate type is fixed after setting it once, this is checked
* here */
if (args->event == NB_EV_VALIDATE) {
/* first get the precise path to the candidate path */
yang_dnode_get_path(args->dnode, xpath_buf, sizeof(xpath_buf));
snprintf(xpath, sizeof(xpath), "%s%s", xpath_buf, "/..");
candidate = nb_running_get_entry_non_rec(NULL, xpath, false);
/* then check if it exists and if the type was provided */
if (candidate
&& candidate->type != SRTE_CANDIDATE_TYPE_UNDEFINED) {
flog_warn(EC_LIB_NB_CB_CONFIG_VALIDATE,
"The candidate type is fixed!");
return NB_ERR_RESOURCE;
} else
return NB_OK;
}
candidate = nb_running_get_entry(args->dnode, NULL, true);
type = yang_dnode_get_enum(args->dnode, NULL);
candidate->type = type;
SET_FLAG(candidate->flags, F_CANDIDATE_MODIFIED);
return NB_OK;
}
/*
* XPath: /frr-pathd:pathd/srte/policy/candidate-path/segment-list-name
*/
int pathd_srte_policy_candidate_path_segment_list_name_modify(
struct nb_cb_modify_args *args)
{
struct srte_candidate *candidate;
const char *segment_list_name;
candidate = nb_running_get_entry(args->dnode, NULL, true);
segment_list_name = yang_dnode_get_string(args->dnode, NULL);
if (args->event != NB_EV_APPLY)
return NB_OK;
candidate->segment_list = srte_segment_list_find(segment_list_name);
candidate->lsp->segment_list = candidate->segment_list;
assert(candidate->segment_list);
SET_FLAG(candidate->flags, F_CANDIDATE_MODIFIED);
return NB_OK;
}
int pathd_srte_policy_candidate_path_segment_list_name_destroy(
struct nb_cb_destroy_args *args)
{
struct srte_candidate *candidate;
if (args->event != NB_EV_APPLY)
return NB_OK;
candidate = nb_running_get_entry(args->dnode, NULL, true);
candidate->segment_list = NULL;
candidate->lsp->segment_list = NULL;
SET_FLAG(candidate->flags, F_CANDIDATE_MODIFIED);
return NB_OK;
}
/*
* XPath: /frr-pathd:pathd/srte/policy/candidate-path/constraints/bandwidth
*/
void pathd_srte_policy_candidate_path_bandwidth_apply_finish(
struct nb_cb_apply_finish_args *args)
{
struct srte_candidate *candidate;
float value;
bool required;
assert(args->context != NULL);
candidate = nb_running_get_entry(args->dnode, NULL, true);
value = (float)yang_dnode_get_dec64(args->dnode, "./value");
required = yang_dnode_get_bool(args->dnode, "./required");
srte_candidate_set_bandwidth(candidate, value, required);
}
int pathd_srte_policy_candidate_path_bandwidth_destroy(
struct nb_cb_destroy_args *args)
{
struct srte_candidate *candidate;
if (args->event != NB_EV_APPLY)
return NB_OK;
assert(args->context != NULL);
candidate = nb_running_get_entry(args->dnode, NULL, true);
srte_candidate_unset_bandwidth(candidate);
return NB_OK;
}

189
pathd/path_nb_state.c Normal file
View File

@ -0,0 +1,189 @@
/*
* Copyright (C) 2020 NetDEF, Inc.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
* Software Foundation; either version 2 of the License, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; see the file COPYING; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <zebra.h>
#include "log.h"
#include "prefix.h"
#include "table.h"
#include "command.h"
#include "northbound.h"
#include "libfrr.h"
#include "pathd/pathd.h"
#include "pathd/path_nb.h"
/*
* XPath: /frr-pathd:pathd/srte/segment-list
*/
const void *pathd_srte_segment_list_get_next(struct nb_cb_get_next_args *args)
{
struct srte_segment_list *segment_list =
(struct srte_segment_list *)args->list_entry;
if (args->list_entry == NULL)
segment_list =
RB_MIN(srte_segment_list_head, &srte_segment_lists);
else
segment_list = RB_NEXT(srte_segment_list_head, segment_list);
return segment_list;
}
int pathd_srte_segment_list_get_keys(struct nb_cb_get_keys_args *args)
{
const struct srte_segment_list *segment_list =
(struct srte_segment_list *)args->list_entry;
args->keys->num = 1;
snprintf(args->keys->key[0], sizeof(args->keys->key[0]), "%s",
segment_list->name);
return NB_OK;
}
const void *
pathd_srte_segment_list_lookup_entry(struct nb_cb_lookup_entry_args *args)
{
return srte_segment_list_find(args->keys->key[0]);
}
/*
* XPath: /frr-pathd:pathd/srte/policy
*/
const void *pathd_srte_policy_get_next(struct nb_cb_get_next_args *args)
{
struct srte_policy *policy = (struct srte_policy *)args->list_entry;
if (args->list_entry == NULL)
policy = RB_MIN(srte_policy_head, &srte_policies);
else
policy = RB_NEXT(srte_policy_head, policy);
return policy;
}
int pathd_srte_policy_get_keys(struct nb_cb_get_keys_args *args)
{
const struct srte_policy *policy =
(struct srte_policy *)args->list_entry;
args->keys->num = 2;
snprintf(args->keys->key[0], sizeof(args->keys->key[0]), "%u",
policy->color);
ipaddr2str(&policy->endpoint, args->keys->key[1],
sizeof(args->keys->key[1]));
return NB_OK;
}
const void *pathd_srte_policy_lookup_entry(struct nb_cb_lookup_entry_args *args)
{
uint32_t color;
struct ipaddr endpoint;
color = yang_str2uint32(args->keys->key[0]);
yang_str2ip(args->keys->key[1], &endpoint);
return srte_policy_find(color, &endpoint);
}
/*
* XPath: /frr-pathd:pathd/srte/policy/is-operational
*/
struct yang_data *
pathd_srte_policy_is_operational_get_elem(struct nb_cb_get_elem_args *args)
{
struct srte_policy *policy = (struct srte_policy *)args->list_entry;
bool is_operational = false;
if (policy->status == SRTE_POLICY_STATUS_UP)
is_operational = true;
return yang_data_new_bool(args->xpath, is_operational);
}
/*
* XPath: /frr-pathd:pathd/srte/policy/candidate-path
*/
const void *
pathd_srte_policy_candidate_path_get_next(struct nb_cb_get_next_args *args)
{
struct srte_policy *policy =
(struct srte_policy *)args->parent_list_entry;
struct srte_candidate *candidate =
(struct srte_candidate *)args->list_entry;
if (args->list_entry == NULL)
candidate =
RB_MIN(srte_candidate_head, &policy->candidate_paths);
else
candidate = RB_NEXT(srte_candidate_head, candidate);
return candidate;
}
int pathd_srte_policy_candidate_path_get_keys(struct nb_cb_get_keys_args *args)
{
const struct srte_candidate *candidate =
(struct srte_candidate *)args->list_entry;
args->keys->num = 1;
snprintf(args->keys->key[0], sizeof(args->keys->key[0]), "%u",
candidate->preference);
return NB_OK;
}
const void *pathd_srte_policy_candidate_path_lookup_entry(
struct nb_cb_lookup_entry_args *args)
{
struct srte_policy *policy =
(struct srte_policy *)args->parent_list_entry;
uint32_t preference;
preference = yang_str2uint32(args->keys->key[0]);
return srte_candidate_find(policy, preference);
}
/*
* XPath: /frr-pathd:pathd/srte/policy/candidate_path/is-best-candidate-path
*/
struct yang_data *
pathd_srte_policy_candidate_path_is_best_candidate_path_get_elem(
struct nb_cb_get_elem_args *args)
{
struct srte_candidate *candidate =
(struct srte_candidate *)args->list_entry;
return yang_data_new_bool(
args->xpath, CHECK_FLAG(candidate->flags, F_CANDIDATE_BEST));
}
/*
* XPath: /frr-pathd:pathd/srte/policy/candidate-path/discriminator
*/
struct yang_data *pathd_srte_policy_candidate_path_discriminator_get_elem(
struct nb_cb_get_elem_args *args)
{
struct srte_candidate *candidate =
(struct srte_candidate *)args->list_entry;
return yang_data_new_uint32(args->xpath, candidate->discriminator);
}

296
pathd/path_zebra.c Normal file
View File

@ -0,0 +1,296 @@
/*
* Copyright (C) 2020 NetDEF, Inc.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
* Software Foundation; either version 2 of the License, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; see the file COPYING; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "thread.h"
#include "log.h"
#include "lib_errors.h"
#include "if.h"
#include "prefix.h"
#include "zclient.h"
#include "network.h"
#include "stream.h"
#include "linklist.h"
#include "nexthop.h"
#include "vrf.h"
#include "typesafe.h"
#include "pathd/pathd.h"
#include "pathd/path_zebra.h"
static struct zclient *zclient;
static struct zclient *zclient_sync;
/* Global Variables */
bool g_has_router_id_v4 = false;
bool g_has_router_id_v6 = false;
struct in_addr g_router_id_v4;
struct in6_addr g_router_id_v6;
pthread_mutex_t g_router_id_v4_mtx = PTHREAD_MUTEX_INITIALIZER;
pthread_mutex_t g_router_id_v6_mtx = PTHREAD_MUTEX_INITIALIZER;
/**
* Gives the IPv4 router ID received from Zebra.
*
* @param router_id The in_addr strucure where to store the router id
* @return true if the router ID was available, false otherwise
*/
bool get_ipv4_router_id(struct in_addr *router_id)
{
bool retval = false;
assert(router_id != NULL);
pthread_mutex_lock(&g_router_id_v4_mtx);
if (g_has_router_id_v4) {
memcpy(router_id, &g_router_id_v4, sizeof(*router_id));
retval = true;
}
pthread_mutex_unlock(&g_router_id_v4_mtx);
return retval;
}
/**
* Gives the IPv6 router ID received from Zebra.
*
* @param router_id The in6_addr strucure where to store the router id
* @return true if the router ID was available, false otherwise
*/
bool get_ipv6_router_id(struct in6_addr *router_id)
{
bool retval = false;
assert(router_id != NULL);
pthread_mutex_lock(&g_router_id_v6_mtx);
if (g_has_router_id_v6) {
memcpy(router_id, &g_router_id_v6, sizeof(*router_id));
retval = true;
}
pthread_mutex_unlock(&g_router_id_v6_mtx);
return retval;
}
static void path_zebra_connected(struct zclient *zclient)
{
struct srte_policy *policy;
zclient_send_reg_requests(zclient, VRF_DEFAULT);
zclient_send_router_id_update(zclient, ZEBRA_ROUTER_ID_ADD, AFI_IP6,
VRF_DEFAULT);
RB_FOREACH (policy, srte_policy_head, &srte_policies) {
struct srte_candidate *candidate;
struct srte_segment_list *segment_list;
candidate = policy->best_candidate;
if (!candidate)
continue;
segment_list = candidate->lsp->segment_list;
if (!segment_list)
continue;
path_zebra_add_sr_policy(policy, segment_list);
}
}
static int path_zebra_sr_policy_notify_status(ZAPI_CALLBACK_ARGS)
{
struct zapi_sr_policy zapi_sr_policy;
struct srte_policy *policy;
struct srte_candidate *best_candidate_path;
if (zapi_sr_policy_notify_status_decode(zclient->ibuf, &zapi_sr_policy))
return -1;
policy = srte_policy_find(zapi_sr_policy.color,
&zapi_sr_policy.endpoint);
if (!policy)
return -1;
best_candidate_path = policy->best_candidate;
if (!best_candidate_path)
return -1;
srte_candidate_status_update(best_candidate_path,
zapi_sr_policy.status);
return 0;
}
/* Router-id update message from zebra. */
static int path_zebra_router_id_update(ZAPI_CALLBACK_ARGS)
{
struct prefix pref;
const char *family;
char buf[PREFIX2STR_BUFFER];
zebra_router_id_update_read(zclient->ibuf, &pref);
if (pref.family == AF_INET) {
pthread_mutex_lock(&g_router_id_v4_mtx);
memcpy(&g_router_id_v4, &pref.u.prefix4,
sizeof(g_router_id_v4));
g_has_router_id_v4 = true;
inet_ntop(AF_INET, &g_router_id_v4, buf, sizeof(buf));
pthread_mutex_unlock(&g_router_id_v4_mtx);
family = "IPv4";
} else if (pref.family == AF_INET6) {
pthread_mutex_lock(&g_router_id_v6_mtx);
memcpy(&g_router_id_v6, &pref.u.prefix6,
sizeof(g_router_id_v6));
g_has_router_id_v6 = true;
inet_ntop(AF_INET6, &g_router_id_v6, buf, sizeof(buf));
pthread_mutex_unlock(&g_router_id_v6_mtx);
family = "IPv6";
} else {
pthread_mutex_unlock(&g_router_id_v4_mtx);
zlog_warn("Unexpected router ID address family for vrf %u: %u",
vrf_id, pref.family);
return 0;
}
pthread_mutex_unlock(&g_router_id_v4_mtx);
zlog_info("%s Router Id updated for VRF %u: %s", family, vrf_id, buf);
return 0;
}
/**
* Adds a segment routing policy to Zebra.
*
* @param policy The policy to add
* @param segment_list The segment list for the policy
*/
void path_zebra_add_sr_policy(struct srte_policy *policy,
struct srte_segment_list *segment_list)
{
struct zapi_sr_policy zp = {};
struct srte_segment_entry *segment;
zp.color = policy->color;
zp.endpoint = policy->endpoint;
strlcpy(zp.name, policy->name, sizeof(zp.name));
zp.segment_list.type = ZEBRA_LSP_SRTE;
zp.segment_list.local_label = policy->binding_sid;
zp.segment_list.label_num = 0;
RB_FOREACH (segment, srte_segment_entry_head, &segment_list->segments)
zp.segment_list.labels[zp.segment_list.label_num++] =
segment->sid_value;
policy->status = SRTE_POLICY_STATUS_GOING_UP;
(void)zebra_send_sr_policy(zclient, ZEBRA_SR_POLICY_SET, &zp);
}
/**
* Deletes a segment policy from Zebra.
*
* @param policy The policy to remove
*/
void path_zebra_delete_sr_policy(struct srte_policy *policy)
{
struct zapi_sr_policy zp = {};
zp.color = policy->color;
zp.endpoint = policy->endpoint;
strlcpy(zp.name, policy->name, sizeof(zp.name));
zp.segment_list.type = ZEBRA_LSP_SRTE;
zp.segment_list.local_label = policy->binding_sid;
zp.segment_list.label_num = 0;
policy->status = SRTE_POLICY_STATUS_DOWN;
(void)zebra_send_sr_policy(zclient, ZEBRA_SR_POLICY_DELETE, &zp);
}
/**
* Allocates a label from Zebra's label manager.
*
* @param label the label to be allocated
* @return 0 if the label has been allocated, -1 otherwise
*/
int path_zebra_request_label(mpls_label_t label)
{
int ret;
uint32_t start, end;
ret = lm_get_label_chunk(zclient_sync, 0, label, 1, &start, &end);
if (ret < 0) {
zlog_warn("%s: error getting label range!", __func__);
return -1;
}
return 0;
}
/**
* Releases a previously allocated label from Zebra's label manager.
*
* @param label The label to release
* @return 0 ifthe label has beel released, -1 otherwise
*/
void path_zebra_release_label(mpls_label_t label)
{
int ret;
ret = lm_release_label_chunk(zclient_sync, label, label);
if (ret < 0)
zlog_warn("%s: error releasing label range!", __func__);
}
static void path_zebra_label_manager_connect(void)
{
/* Connect to label manager. */
while (zclient_socket_connect(zclient_sync) < 0) {
zlog_warn("%s: error connecting synchronous zclient!",
__func__);
sleep(1);
}
set_nonblocking(zclient_sync->sock);
/* Send hello to notify zebra this is a synchronous client */
while (zclient_send_hello(zclient_sync) < 0) {
zlog_warn("%s: Error sending hello for synchronous zclient!",
__func__);
sleep(1);
}
while (lm_label_manager_connect(zclient_sync, 0) != 0) {
zlog_warn("%s: error connecting to label manager!", __func__);
sleep(1);
}
}
/**
* Initializes Zebra asynchronous connection.
*
* @param master The master thread
*/
void path_zebra_init(struct thread_master *master)
{
struct zclient_options options = zclient_options_default;
options.synchronous = true;
/* Initialize asynchronous zclient. */
zclient = zclient_new(master, &zclient_options_default);
zclient_init(zclient, ZEBRA_ROUTE_SRTE, 0, &pathd_privs);
zclient->zebra_connected = path_zebra_connected;
zclient->sr_policy_notify_status = path_zebra_sr_policy_notify_status;
zclient->router_id_update = path_zebra_router_id_update;
/* Initialize special zclient for synchronous message exchanges. */
zclient_sync = zclient_new(master, &options);
zclient_sync->sock = -1;
zclient_sync->redist_default = ZEBRA_ROUTE_SRTE;
zclient_sync->instance = 1;
zclient_sync->privs = &pathd_privs;
/* Connect to the LM. */
path_zebra_label_manager_connect();
}

34
pathd/path_zebra.h Normal file
View File

@ -0,0 +1,34 @@
/*
* Copyright (C) 2020 NetDEF, Inc.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
* Software Foundation; either version 2 of the License, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; see the file COPYING; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef _FRR_PATH_MPLS_H_
#define _FRR_PATH_MPLS_H_
#include <zebra.h>
#include "pathd/pathd.h"
bool get_ipv4_router_id(struct in_addr *router_id);
bool get_ipv6_router_id(struct in6_addr *router_id);
void path_zebra_add_sr_policy(struct srte_policy *policy,
struct srte_segment_list *segment_list);
void path_zebra_delete_sr_policy(struct srte_policy *policy);
int path_zebra_request_label(mpls_label_t label);
void path_zebra_release_label(mpls_label_t label);
void path_zebra_init(struct thread_master *master);
#endif /* _FRR_PATH_MPLS_H_ */

1127
pathd/pathd.c Normal file

File diff suppressed because it is too large Load Diff

33
pathd/pathd.conf.sample Normal file
View File

@ -0,0 +1,33 @@
! Default pathd configuration sample
!
password frr
log stdout
segment-routing
traffic-eng
segment-list test1
index 10 mpls label 123
index 20 mpls label 456
!
segment-list test2
index 10 mpls label 321
index 20 mpls label 654
!
policy color 1 endpoint 1.1.1.1
name one
binding-sid 100
candidate-path preference 100 name test1 explicit segment-list test1
candidate-path preference 200 name test2 explicit segment-list test2
!
policy color 2 endpoint 2.2.2.2
name two
binding-sid 101
candidate-path preference 100 name def explicit segment-list test2
candidate-path preference 200 name dyn dynamic
bandwidth 12345
metric bound abc 16 required
metric te 10
!
!
!
!

412
pathd/pathd.h Normal file
View File

@ -0,0 +1,412 @@
/*
* Copyright (C) 2020 NetDEF, Inc.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
* Software Foundation; either version 2 of the License, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; see the file COPYING; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef _FRR_PATHD_H_
#define _FRR_PATHD_H_
#include "lib/mpls.h"
#include "lib/ipaddr.h"
#include "lib/srte.h"
#include "lib/hook.h"
enum srte_protocol_origin {
SRTE_ORIGIN_UNDEFINED = 0,
SRTE_ORIGIN_PCEP = 1,
SRTE_ORIGIN_BGP = 2,
SRTE_ORIGIN_LOCAL = 3,
};
enum srte_policy_status {
SRTE_POLICY_STATUS_UNKNOWN = 0,
SRTE_POLICY_STATUS_DOWN = 1,
SRTE_POLICY_STATUS_UP = 2,
SRTE_POLICY_STATUS_GOING_DOWN = 3,
SRTE_POLICY_STATUS_GOING_UP = 4
};
enum srte_candidate_type {
SRTE_CANDIDATE_TYPE_UNDEFINED = 0,
SRTE_CANDIDATE_TYPE_EXPLICIT = 1,
SRTE_CANDIDATE_TYPE_DYNAMIC = 2,
};
enum srte_candidate_metric_type {
/* IGP metric */
SRTE_CANDIDATE_METRIC_TYPE_IGP = 1,
/* TE metric */
SRTE_CANDIDATE_METRIC_TYPE_TE = 2,
/* Hop Counts */
SRTE_CANDIDATE_METRIC_TYPE_HC = 3,
/* Aggregate bandwidth consumption */
SRTE_CANDIDATE_METRIC_TYPE_ABC = 4,
/* Load of the most loaded link */
SRTE_CANDIDATE_METRIC_TYPE_LMLL = 5,
/* Cumulative IGP cost */
SRTE_CANDIDATE_METRIC_TYPE_CIGP = 6,
/* Cumulative TE cost */
SRTE_CANDIDATE_METRIC_TYPE_CTE = 7,
/* P2MP IGP metric */
SRTE_CANDIDATE_METRIC_TYPE_PIGP = 8,
/* P2MP TE metric */
SRTE_CANDIDATE_METRIC_TYPE_PTE = 9,
/* P2MP hop count metric */
SRTE_CANDIDATE_METRIC_TYPE_PHC = 10,
/* Segment-ID (SID) Depth */
SRTE_CANDIDATE_METRIC_TYPE_MSD = 11,
/* Path Delay metric */
SRTE_CANDIDATE_METRIC_TYPE_PD = 12,
/* Path Delay Variation metric */
SRTE_CANDIDATE_METRIC_TYPE_PDV = 13,
/* Path Loss metric */
SRTE_CANDIDATE_METRIC_TYPE_PL = 14,
/* P2MP Path Delay metric */
SRTE_CANDIDATE_METRIC_TYPE_PPD = 15,
/* P2MP Path Delay variation metric */
SRTE_CANDIDATE_METRIC_TYPE_PPDV = 16,
/* P2MP Path Loss metric */
SRTE_CANDIDATE_METRIC_TYPE_PPL = 17,
/* Number of adaptations on a path */
SRTE_CANDIDATE_METRIC_TYPE_NAP = 18,
/* Number of layers on a path */
SRTE_CANDIDATE_METRIC_TYPE_NLP = 19,
/* Domain Count metric */
SRTE_CANDIDATE_METRIC_TYPE_DC = 20,
/* Border Node Count metric */
SRTE_CANDIDATE_METRIC_TYPE_BNC = 21,
};
#define MAX_METRIC_TYPE 21
enum srte_segment_nai_type {
SRTE_SEGMENT_NAI_TYPE_NONE = 0,
SRTE_SEGMENT_NAI_TYPE_IPV4_NODE = 1,
SRTE_SEGMENT_NAI_TYPE_IPV6_NODE = 2,
SRTE_SEGMENT_NAI_TYPE_IPV4_ADJACENCY = 3,
SRTE_SEGMENT_NAI_TYPE_IPV6_ADJACENCY = 4,
SRTE_SEGMENT_NAI_TYPE_IPV4_UNNUMBERED_ADJACENCY = 5
};
enum objfun_type {
OBJFUN_UNDEFINED = 0,
/* Minimum Cost Path [RFC5541] */
OBJFUN_MCP = 1,
/* Minimum Load Path [RFC5541] */
OBJFUN_MLP = 2,
/* Maximum residual Bandwidth Path [RFC5541] */
OBJFUN_MBP = 3,
/* Minimize aggregate Bandwidth Consumption [RFC5541] */
OBJFUN_MBC = 4,
/* Minimize the Load of the most loaded Link [RFC5541] */
OBJFUN_MLL = 5,
/* Minimize the Cumulative Cost of a set of paths [RFC5541] */
OBJFUN_MCC = 6,
/* Shortest Path Tree [RFC8306] */
OBJFUN_SPT = 7,
/* Minimum Cost Tree [RFC8306] */
OBJFUN_MCT = 8,
/* Minimum Packet Loss Path [RFC8233] */
OBJFUN_MPLP = 9,
/* Maximum Under-Utilized Path [RFC8233] */
OBJFUN_MUP = 10,
/* Maximum Reserved Under-Utilized Path [RFC8233] */
OBJFUN_MRUP = 11,
/* Minimize the number of Transit Domains [RFC8685] */
OBJFUN_MTD = 12,
/* Minimize the number of Border Nodes [RFC8685] */
OBJFUN_MBN = 13,
/* Minimize the number of Common Transit Domains [RFC8685] */
OBJFUN_MCTD = 14,
/* Minimize the number of Shared Links [RFC8800] */
OBJFUN_MSL = 15,
/* Minimize the number of Shared SRLGs [RFC8800] */
OBJFUN_MSS = 16,
/* Minimize the number of Shared Nodes [RFC8800] */
OBJFUN_MSN = 17,
};
#define MAX_OBJFUN_TYPE 17
enum affinity_filter_type {
AFFINITY_FILTER_UNDEFINED = 0,
AFFINITY_FILTER_EXCLUDE_ANY = 1,
AFFINITY_FILTER_INCLUDE_ANY = 2,
AFFINITY_FILTER_INCLUDE_ALL = 3,
};
#define MAX_AFFINITY_FILTER_TYPE 3
struct srte_segment_list;
struct srte_segment_entry {
RB_ENTRY(srte_segment_entry) entry;
/* The segment list the entry belong to */
struct srte_segment_list *segment_list;
/* Index of the Label. */
uint32_t index;
/* Label Value. */
mpls_label_t sid_value;
/* NAI Type */
enum srte_segment_nai_type nai_type;
/* NAI local address when nai type is not NONE */
struct ipaddr nai_local_addr;
/* NAI local interface when nai type is not IPv4 unnumbered adjacency */
uint32_t nai_local_iface;
/* NAI local interface when nai type is IPv4 or IPv6 adjacency */
struct ipaddr nai_remote_addr;
/* NAI remote interface when nai type is not IPv4 unnumbered adjacency
*/
uint32_t nai_remote_iface;
};
RB_HEAD(srte_segment_entry_head, srte_segment_entry);
RB_PROTOTYPE(srte_segment_entry_head, srte_segment_entry, entry,
srte_segment_entry_compare)
struct srte_segment_list {
RB_ENTRY(srte_segment_list) entry;
/* Name of the Segment List. */
char name[64];
/* The Protocol-Origin. */
enum srte_protocol_origin protocol_origin;
/* The Originator */
char originator[64];
/* Nexthops. */
struct srte_segment_entry_head segments;
/* Status flags. */
uint16_t flags;
#define F_SEGMENT_LIST_NEW 0x0002
#define F_SEGMENT_LIST_MODIFIED 0x0004
#define F_SEGMENT_LIST_DELETED 0x0008
};
RB_HEAD(srte_segment_list_head, srte_segment_list);
RB_PROTOTYPE(srte_segment_list_head, srte_segment_list, entry,
srte_segment_list_compare)
struct srte_metric {
uint16_t flags;
#define F_METRIC_IS_DEFINED 0x0001
#define F_METRIC_IS_REQUIRED 0x0002
#define F_METRIC_IS_BOUND 0x0004
#define F_METRIC_IS_COMPUTED 0x0008
float value;
};
/* Runtime information about the candidate path */
struct srte_lsp {
/* Backpointer to the Candidate Path. */
struct srte_candidate *candidate;
/* The associated Segment List. */
struct srte_segment_list *segment_list;
/* The Protocol-Origin. */
enum srte_protocol_origin protocol_origin;
/* The Originator */
char originator[64];
/* The Discriminator */
uint32_t discriminator;
/* Flags. */
uint32_t flags;
/* Metrics LSP Values */
struct srte_metric metrics[MAX_METRIC_TYPE];
/* Bandwidth Configured Value */
float bandwidth;
/* The objective function in used */
enum objfun_type objfun;
};
/* Configured candidate path */
struct srte_candidate {
RB_ENTRY(srte_candidate) entry;
/* Backpointer to SR Policy */
struct srte_policy *policy;
/* The LSP associated with this candidate path. */
struct srte_lsp *lsp;
/* Administrative preference. */
uint32_t preference;
/* Symbolic Name. */
char name[64];
/* The associated Segment List. */
struct srte_segment_list *segment_list;
/* The Protocol-Origin. */
enum srte_protocol_origin protocol_origin;
/* The Originator */
char originator[64];
/* The Discriminator */
uint32_t discriminator;
/* The Type (explicit or dynamic) */
enum srte_candidate_type type;
/* Flags. */
uint32_t flags;
#define F_CANDIDATE_BEST 0x0001
#define F_CANDIDATE_NEW 0x0002
#define F_CANDIDATE_MODIFIED 0x0004
#define F_CANDIDATE_DELETED 0x0008
#define F_CANDIDATE_HAS_BANDWIDTH 0x0100
#define F_CANDIDATE_REQUIRED_BANDWIDTH 0x0200
#define F_CANDIDATE_HAS_OBJFUN 0x0400
#define F_CANDIDATE_REQUIRED_OBJFUN 0x0800
#define F_CANDIDATE_HAS_EXCLUDE_ANY 0x1000
#define F_CANDIDATE_HAS_INCLUDE_ANY 0x2000
#define F_CANDIDATE_HAS_INCLUDE_ALL 0x4000
/* Metrics Configured Values */
struct srte_metric metrics[MAX_METRIC_TYPE];
/* Bandwidth Configured Value */
float bandwidth;
/* Configured objective functions */
enum objfun_type objfun;
/* Path constraints attribute filters */
uint32_t affinity_filters[MAX_AFFINITY_FILTER_TYPE];
/* Hooks delaying timer */
struct thread *hook_timer;
};
RB_HEAD(srte_candidate_head, srte_candidate);
RB_PROTOTYPE(srte_candidate_head, srte_candidate, entry, srte_candidate_compare)
struct srte_policy {
RB_ENTRY(srte_policy) entry;
/* Color */
uint32_t color;
/* Endpoint */
struct ipaddr endpoint;
/* Name */
char name[64];
/* Binding SID */
mpls_label_t binding_sid;
/* Operational Status of the policy */
enum srte_policy_status status;
/* Best candidate path. */
struct srte_candidate *best_candidate;
/* Candidate Paths */
struct srte_candidate_head candidate_paths;
/* Status flags. */
uint16_t flags;
#define F_POLICY_NEW 0x0002
#define F_POLICY_MODIFIED 0x0004
#define F_POLICY_DELETED 0x0008
};
RB_HEAD(srte_policy_head, srte_policy);
RB_PROTOTYPE(srte_policy_head, srte_policy, entry, srte_policy_compare)
DECLARE_HOOK(pathd_candidate_created, (struct srte_candidate * candidate),
(candidate))
DECLARE_HOOK(pathd_candidate_updated, (struct srte_candidate * candidate),
(candidate))
DECLARE_HOOK(pathd_candidate_removed, (struct srte_candidate * candidate),
(candidate))
extern struct srte_segment_list_head srte_segment_lists;
extern struct srte_policy_head srte_policies;
extern struct zebra_privs_t pathd_privs;
/* master thread, defined in path_main.c */
extern struct thread_master *master;
/* pathd.c */
struct srte_segment_list *srte_segment_list_add(const char *name);
void srte_segment_list_del(struct srte_segment_list *segment_list);
struct srte_segment_list *srte_segment_list_find(const char *name);
struct srte_segment_entry *
srte_segment_entry_add(struct srte_segment_list *segment_list, uint32_t index);
void srte_segment_entry_del(struct srte_segment_entry *segment);
void srte_segment_entry_set_nai(struct srte_segment_entry *segment,
enum srte_segment_nai_type type,
struct ipaddr *local_ip, uint32_t local_iface,
struct ipaddr *remote_ip,
uint32_t remote_iface);
struct srte_policy *srte_policy_add(uint32_t color, struct ipaddr *endpoint);
void srte_policy_del(struct srte_policy *policy);
struct srte_policy *srte_policy_find(uint32_t color, struct ipaddr *endpoint);
void srte_policy_update_binding_sid(struct srte_policy *policy,
uint32_t binding_sid);
void srte_apply_changes(void);
void srte_policy_apply_changes(struct srte_policy *policy);
struct srte_candidate *srte_candidate_add(struct srte_policy *policy,
uint32_t preference);
void srte_candidate_del(struct srte_candidate *candidate);
void srte_candidate_set_bandwidth(struct srte_candidate *candidate,
float bandwidth, bool required);
void srte_candidate_unset_bandwidth(struct srte_candidate *candidate);
void srte_candidate_set_metric(struct srte_candidate *candidate,
enum srte_candidate_metric_type type,
float value, bool required, bool is_cound,
bool is_computed);
void srte_candidate_unset_metric(struct srte_candidate *candidate,
enum srte_candidate_metric_type type);
void srte_candidate_set_objfun(struct srte_candidate *candidate, bool required,
enum objfun_type type);
void srte_candidate_unset_objfun(struct srte_candidate *candidate);
void srte_candidate_set_affinity_filter(struct srte_candidate *candidate,
enum affinity_filter_type type,
uint32_t filter);
void srte_candidate_unset_affinity_filter(struct srte_candidate *candidate,
enum affinity_filter_type type);
void srte_lsp_set_bandwidth(struct srte_lsp *lsp, float bandwidth,
bool required);
void srte_lsp_unset_bandwidth(struct srte_lsp *lsp);
void srte_lsp_set_metric(struct srte_lsp *lsp,
enum srte_candidate_metric_type type, float value,
bool required, bool is_cound, bool is_computed);
void srte_lsp_unset_metric(struct srte_lsp *lsp,
enum srte_candidate_metric_type type);
struct srte_candidate *srte_candidate_find(struct srte_policy *policy,
uint32_t preference);
struct srte_segment_entry *
srte_segment_entry_find(struct srte_segment_list *segment_list, uint32_t index);
void srte_candidate_status_update(struct srte_candidate *candidate, int status);
void srte_candidate_unset_segment_list(const char *originator, bool force);
const char *srte_origin2str(enum srte_protocol_origin origin);
/* path_cli.c */
void path_cli_init(void);
#endif /* _FRR_PATHD_H_ */

48
pathd/subdir.am Normal file
View File

@ -0,0 +1,48 @@
#
# pathd
#
if PATHD
noinst_LIBRARIES += pathd/libpath.a
sbin_PROGRAMS += pathd/pathd
dist_examples_DATA += pathd/pathd.conf.sample
vtysh_scan += $(top_srcdir)/pathd/path_cli.c
vtysh_daemons += pathd
# TODO add man page
#man8 += $(MANBUILD)/pathd.8
endif
pathd_libpath_a_SOURCES = \
pathd/path_cli.c \
pathd/path_debug.c \
pathd/path_errors.c \
pathd/path_main.c \
pathd/path_memory.c \
pathd/path_nb.c \
pathd/path_nb_config.c \
pathd/path_nb_state.c \
pathd/path_zebra.c \
pathd/pathd.c \
# end
clippy_scan += \
pathd/path_cli.c \
# end
noinst_HEADERS += \
pathd/path_debug.h \
pathd/path_errors.h \
pathd/path_memory.h \
pathd/path_nb.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)

View File

@ -27,6 +27,7 @@
%{!?with_vrrpd: %global with_vrrpd 1 }
%{!?with_rtadv: %global with_rtadv 1 }
%{!?with_watchfrr: %global with_watchfrr 1 }
%{!?with_pathd: %global with_pathd 1 }
# user and group
%{!?frr_user: %global frr_user frr }
@ -87,7 +88,7 @@
%{!?frr_gid: %global frr_gid 92 }
%{!?vty_gid: %global vty_gid 85 }
%define daemon_list zebra ripd ospfd bgpd isisd ripngd ospf6d pbrd staticd bfdd fabricd
%define daemon_list zebra ripd ospfd bgpd isisd ripngd ospf6d pbrd staticd bfdd fabricd pathd
%if %{with_ldpd}
%define daemon_ldpd ldpd
@ -143,7 +144,13 @@
%define daemon_bfdd ""
%endif
%define all_daemons %{daemon_list} %{daemon_ldpd} %{daemon_pimd} %{daemon_nhrpd} %{daemon_eigrpd} %{daemon_babeld} %{daemon_watchfrr} %{daemon_pbrd} %{daemon_bfdd} %{daemon_vrrpd}
%if %{with_pathd}
%define daemon_pathd pathd
%else
%define daemon_pathd ""
%endif
%define all_daemons %{daemon_list} %{daemon_ldpd} %{daemon_pimd} %{daemon_nhrpd} %{daemon_eigrpd} %{daemon_babeld} %{daemon_watchfrr} %{daemon_pbrd} %{daemon_bfdd} %{daemon_vrrpd} %{daemon_pathd}
#release sub-revision (the two digits after the CONFDATE)
%{!?release_rev: %global release_rev 01 }
@ -397,6 +404,11 @@ routing state through standard SNMP MIBs.
--enable-bfdd \
%else
--disable-bfdd \
%endif
%if %{with_pathd}
--enable-pathd \
%else
--disable-pathd \
%endif
--enable-snmp
# end
@ -526,6 +538,9 @@ zebra_spec_add_service fabricd 2618/tcp "Fabricd vty"
%if %{with_vrrpd}
zebra_spec_add_service vrrpd 2619/tcp "VRRPd vty"
%endif
%if %{with_pathd}
zebra_spec_add_service pathd 2620/tcp "Pathd vty"
%endif
%if "%{initsystem}" == "systemd"
for daemon in %all_daemons ; do
@ -681,6 +696,9 @@ fi
%if %{with_bfdd}
%{_sbindir}/bfdd
%endif
%if %{with_pathd}
%{_sbindir}/pathd
%endif
%{_libdir}/libfrr.so*
%{_libdir}/libfrrcares*
%{_libdir}/libfrrospf*
@ -798,6 +816,9 @@ sed -i 's/ -M rpki//' %{_sysconfdir}/frr/daemons
- migrate route-maps to use northbound interface
- plus countless bug fixes and other improvements
* Mon Jun 15 2020 Sascha Kattelmann <sascha@netdef.org>
- Add Pathd support
* Wed May 06 2020 David Lamparter <equinox@opensourcerouting.org> - 7.3.1
- upstream 7.3.1

View File

@ -0,0 +1,19 @@
log file zebra.log
!
hostname dst
!
debug zebra kernel
debug zebra packet
debug zebra mpls
!
interface lo
ip address 9.9.9.2/32
ipv6 address 2001:db8:1066::2/128
!
interface eth-rt6
ip address 10.0.11.2/24
!
ip forwarding
!
line vty
!

View File

@ -0,0 +1,16 @@
log file bgpd.log
!
router bgp 1
bgp router-id 1.1.1.1
neighbor 6.6.6.6 remote-as 1
neighbor 6.6.6.6 update-source lo
!
address-family ipv4 unicast
redistribute static
neighbor 6.6.6.6 next-hop-self
neighbor 6.6.6.6 route-map SET_SR_POLICY in
exit-address-family
!
route-map SET_SR_POLICY permit 10
set sr-te color 1
!

View File

@ -0,0 +1,30 @@
password 1
hostname rt1
log file isisd.log
!
debug isis events
debug isis route-events
debug isis spf-events
debug isis sr-events
debug isis lsp-gen
!
interface lo
ip router isis 1
ipv6 router isis 1
isis passive
!
interface eth-sw1
ip router isis 1
ipv6 router isis 1
isis hello-multiplier 3
!
router isis 1
net 49.0000.0000.0000.0001.00
is-type level-1
topology ipv6-unicast
segment-routing on
segment-routing global-block 16000 23999
segment-routing node-msd 8
segment-routing prefix 1.1.1.1/32 index 10
segment-routing prefix 2001:db8:1000::1/128 index 11
!

View File

@ -0,0 +1,21 @@
log file pathd.log
!
hostname rt1
!
segment-routing
traffic-eng
segment-list default
index 10 mpls label 16050
index 20 mpls label 16060
!
segment-list test
index 10 mpls label 16020
index 20 mpls label 16040
index 30 mpls label 16060
!
policy color 1 endpoint 6.6.6.6
name default
binding-sid 1111
!
!
!

View File

@ -0,0 +1,91 @@
{
"1111":{
"inLabel":1111,
"installed":true,
"nexthops":[
{
"type":"SR-TE",
"outLabel":16050,
"outLabelStack":[
16050,
16060
],
"distance":150,
"installed":true,
"nexthop":"10.0.1.3"
}
]
},
"16020":{
"inLabel":16020,
"installed":true,
"nexthops":[
{
"type":"SR (IS-IS)",
"outLabel":16020,
"distance":150,
"installed":true,
"nexthop":"10.0.1.2"
}
]
},
"16030":{
"inLabel":16030,
"installed":true,
"nexthops":[
{
"type":"SR (IS-IS)",
"outLabel":16030,
"distance":150,
"installed":true,
"nexthop":"10.0.1.3"
}
]
},
"16040":{
"inLabel":16040,
"installed":true,
"nexthops":[
{
"type":"SR (IS-IS)",
"outLabel":16040,
"distance":150,
"installed":true,
"nexthop":"10.0.1.2"
}
]
},
"16050":{
"inLabel":16050,
"installed":true,
"nexthops":[
{
"type":"SR (IS-IS)",
"outLabel":16050,
"distance":150,
"installed":true,
"nexthop":"10.0.1.3"
}
]
},
"16060":{
"inLabel":16060,
"installed":true,
"nexthops":[
{
"type":"SR (IS-IS)",
"outLabel":16060,
"distance":150,
"installed":true,
"nexthop":"10.0.1.3"
},
{
"type":"SR (IS-IS)",
"outLabel":16060,
"distance":150,
"installed":true,
"nexthop":"10.0.1.2"
}
]
}
}

View File

@ -0,0 +1,74 @@
{
"16020":{
"inLabel":16020,
"installed":true,
"nexthops":[
{
"type":"SR (IS-IS)",
"outLabel":16020,
"distance":150,
"installed":true,
"nexthop":"10.0.1.2"
}
]
},
"16030":{
"inLabel":16030,
"installed":true,
"nexthops":[
{
"type":"SR (IS-IS)",
"outLabel":16030,
"distance":150,
"installed":true,
"nexthop":"10.0.1.3"
}
]
},
"16040":{
"inLabel":16040,
"installed":true,
"nexthops":[
{
"type":"SR (IS-IS)",
"outLabel":16040,
"distance":150,
"installed":true,
"nexthop":"10.0.1.2"
}
]
},
"16050":{
"inLabel":16050,
"installed":true,
"nexthops":[
{
"type":"SR (IS-IS)",
"outLabel":16050,
"distance":150,
"installed":true,
"nexthop":"10.0.1.3"
}
]
},
"16060":{
"inLabel":16060,
"installed":true,
"nexthops":[
{
"type":"SR (IS-IS)",
"outLabel":16060,
"distance":150,
"installed":true,
"nexthop":"10.0.1.3"
},
{
"type":"SR (IS-IS)",
"outLabel":16060,
"distance":150,
"installed":true,
"nexthop":"10.0.1.2"
}
]
}
}

View File

@ -0,0 +1,13 @@
{
"frr-pathd:pathd": {
"srte": {
"policy": [
{
"color": 1,
"endpoint": "6.6.6.6",
"is-operational": false
}
]
}
}
}

View File

@ -0,0 +1,20 @@
{
"frr-pathd:pathd": {
"srte": {
"policy": [
{
"color": 1,
"endpoint": "6.6.6.6",
"is-operational": true,
"candidate-path": [
{
"preference": 100,
"discriminator": "*",
"is-best-candidate-path": true
}
]
}
]
}
}
}

View File

@ -0,0 +1,20 @@
{
"frr-pathd:pathd": {
"srte": {
"policy": [
{
"color": 1,
"endpoint": "6.6.6.6",
"is-operational": true,
"candidate-path": [
{
"preference": 100,
"discriminator": "*",
"is-best-candidate-path": true
}
]
}
]
}
}
}

View File

@ -0,0 +1,25 @@
{
"frr-pathd:pathd": {
"srte": {
"policy": [
{
"color": 1,
"endpoint": "6.6.6.6",
"is-operational": true,
"candidate-path": [
{
"preference": 100,
"discriminator": "*",
"is-best-candidate-path": false
},
{
"preference": 200,
"discriminator": "*",
"is-best-candidate-path": true
}
]
}
]
}
}
}

View File

@ -0,0 +1,20 @@
{
"1111":{
"inLabel":1111,
"installed":true,
"nexthops":[
{
"type":"SR-TE",
"outLabel":16020,
"outLabelStack":[
16020,
16040,
16060
],
"distance":150,
"installed":true,
"nexthop":"10.0.1.2"
}
]
}
}

View File

@ -0,0 +1,21 @@
{
"1111":{
"inLabel":1111,
"installed":true,
"nexthops":[
{
"type":"SR-TE",
"outLabel":16020,
"outLabelStack":[
16020,
16040,
16050,
16060
],
"distance":150,
"installed":true,
"nexthop":"10.0.1.2"
}
]
}
}

View File

@ -0,0 +1,21 @@
{
"1111":{
"inLabel":1111,
"installed":true,
"nexthops":[
{
"type":"SR-TE",
"outLabel":16020,
"outLabelStack":[
16020,
16040,
16030,
16060
],
"distance":150,
"installed":true,
"nexthop":"10.0.1.2"
}
]
}
}

View File

@ -0,0 +1,29 @@
{
"9.9.9.2\/32":[
{
"prefix":"9.9.9.2\/32",
"protocol":"bgp",
"installed":true,
"nexthops":[
{
"ip":"6.6.6.6",
"afi":"ipv4",
"active":true,
"recursive":true,
"srteColor":1
},
{
"fib":true,
"ip":"10.0.1.3",
"afi":"ipv4",
"interfaceName":"eth-sw1",
"active":true,
"labels":[
16050,
16060
]
}
]
}
]
}

View File

@ -0,0 +1,38 @@
{
"9.9.9.2\/32":[
{
"prefix":"9.9.9.2\/32",
"protocol":"bgp",
"installed":true,
"nexthops":[
{
"ip":"6.6.6.6",
"afi":"ipv4",
"active":true,
"recursive":true,
"srteColor":1
},
{
"fib":true,
"ip":"10.0.1.2",
"afi":"ipv4",
"interfaceName":"eth-sw1",
"active":true,
"labels":[
16060
]
},
{
"fib":true,
"ip":"10.0.1.3",
"afi":"ipv4",
"interfaceName":"eth-sw1",
"active":true,
"labels":[
16060
]
}
]
}
]
}

View File

@ -0,0 +1,20 @@
{
"frr-pathd:pathd": {
"srte": {
"policy": [
{
"color": 1,
"endpoint": "6.6.6.6",
"is-operational": true,
"candidate-path": [
{
"preference": 100,
"discriminator": "*",
"is-best-candidate-path": true
}
]
}
]
}
}
}

View File

@ -0,0 +1,20 @@
{
"frr-pathd:pathd": {
"srte": {
"policy": [
{
"color": 1,
"endpoint": "6.6.6.6",
"is-operational": false,
"candidate-path": [
{
"preference": 100,
"discriminator": "*",
"is-best-candidate-path": true
}
]
}
]
}
}
}

View File

@ -0,0 +1,19 @@
log file zebra.log
!
hostname rt1
!
debug zebra kernel
debug zebra packet
debug zebra mpls
!
interface lo
ip address 1.1.1.1/32
ipv6 address 2001:db8:1000::1/128
!
interface eth-sw1
ip address 10.0.1.1/24
!
ip forwarding
!
line vty
!

View File

@ -0,0 +1,41 @@
hostname rt2
log file isisd.log
!
debug isis events
debug isis route-events
debug isis spf-events
debug isis sr-events
debug isis lsp-gen
!
interface lo
ip router isis 1
ipv6 router isis 1
isis passive
!
interface eth-sw1
ip router isis 1
ipv6 router isis 1
isis hello-multiplier 3
!
interface eth-rt4-1
ip router isis 1
ipv6 router isis 1
isis network point-to-point
isis hello-multiplier 3
!
interface eth-rt4-2
ip router isis 1
ipv6 router isis 1
isis network point-to-point
isis hello-multiplier 3
!
router isis 1
net 49.0000.0000.0000.0002.00
is-type level-1
topology ipv6-unicast
segment-routing on
segment-routing global-block 16000 23999
segment-routing node-msd 8
segment-routing prefix 2.2.2.2/32 index 20 no-php-flag
segment-routing prefix 2001:db8:1000::2/128 index 21 no-php-flag
!

View File

@ -0,0 +1,25 @@
log file zebra.log
!
hostname rt2
!
debug zebra kernel
debug zebra packet
debug zebra mpls
!
interface lo
ip address 2.2.2.2/32
ipv6 address 2001:db8:1000::2/128
!
interface eth-sw1
ip address 10.0.1.2/24
!
interface eth-rt4-1
ip address 10.0.2.2/24
!
interface eth-rt4-2
ip address 10.0.3.2/24
!
ip forwarding
!
line vty
!

View File

@ -0,0 +1,41 @@
hostname rt3
log file isisd.log
!
debug isis events
debug isis route-events
debug isis spf-events
debug isis sr-events
debug isis lsp-gen
!
interface lo
ip router isis 1
ipv6 router isis 1
isis passive
!
interface eth-sw1
ip router isis 1
ipv6 router isis 1
isis hello-multiplier 3
!
interface eth-rt5-1
ip router isis 1
ipv6 router isis 1
isis network point-to-point
isis hello-multiplier 3
!
interface eth-rt5-2
ip router isis 1
ipv6 router isis 1
isis network point-to-point
isis hello-multiplier 3
!
router isis 1
net 49.0000.0000.0000.0003.00
is-type level-1
topology ipv6-unicast
segment-routing on
segment-routing global-block 16000 23999
segment-routing node-msd 8
segment-routing prefix 3.3.3.3/32 index 30 no-php-flag
segment-routing prefix 2001:db8:1000::3/128 index 31 no-php-flag
!

View File

@ -0,0 +1,25 @@
log file zebra.log
!
hostname rt3
!
debug zebra kernel
debug zebra packet
debug zebra mpls
!
interface lo
ip address 3.3.3.3/32
ipv6 address 2001:db8:1000::3/128
!
interface eth-sw1
ip address 10.0.1.3/24
!
interface eth-rt5-1
ip address 10.0.4.3/24
!
interface eth-rt5-2
ip address 10.0.5.3/24
!
ip forwarding
!
line vty
!

View File

@ -0,0 +1,48 @@
hostname rt4
log file isisd.log
!
debug isis events
debug isis route-events
debug isis spf-events
debug isis sr-events
debug isis lsp-gen
!
interface lo
ip router isis 1
ipv6 router isis 1
isis passive
!
interface eth-rt2-1
ip router isis 1
ipv6 router isis 1
isis network point-to-point
isis hello-multiplier 3
!
interface eth-rt2-2
ip router isis 1
ipv6 router isis 1
isis network point-to-point
isis hello-multiplier 3
!
interface eth-rt5
ip router isis 1
ipv6 router isis 1
isis network point-to-point
isis hello-multiplier 3
!
interface eth-rt6
ip router isis 1
ipv6 router isis 1
isis network point-to-point
isis hello-multiplier 3
!
router isis 1
net 49.0000.0000.0000.0004.00
is-type level-1
topology ipv6-unicast
segment-routing on
segment-routing global-block 16000 23999
segment-routing node-msd 8
segment-routing prefix 4.4.4.4/32 index 40 no-php-flag
segment-routing prefix 2001:db8:1000::4/128 index 41 no-php-flag
!

View File

@ -0,0 +1,28 @@
log file zebra.log
!
hostname rt4
!
debug zebra kernel
debug zebra packet
debug zebra mpls
!
interface lo
ip address 4.4.4.4/32
ipv6 address 2001:db8:1000::4/128
!
interface eth-rt2-1
ip address 10.0.2.4/24
!
interface eth-rt2-2
ip address 10.0.3.4/24
!
interface eth-rt5
ip address 10.0.6.4/24
!
interface eth-rt6
ip address 10.0.7.4/24
!
ip forwarding
!
line vty
!

View File

@ -0,0 +1,48 @@
hostname rt5
log file isisd.log
!
debug isis events
debug isis route-events
debug isis spf-events
debug isis sr-events
debug isis lsp-gen
!
interface lo
ip router isis 1
ipv6 router isis 1
isis passive
!
interface eth-rt3-1
ip router isis 1
ipv6 router isis 1
isis network point-to-point
isis hello-multiplier 3
!
interface eth-rt3-2
ip router isis 1
ipv6 router isis 1
isis network point-to-point
isis hello-multiplier 3
!
interface eth-rt4
ip router isis 1
ipv6 router isis 1
isis network point-to-point
isis hello-multiplier 3
!
interface eth-rt6
ip router isis 1
ipv6 router isis 1
isis network point-to-point
isis hello-multiplier 3
!
router isis 1
net 49.0000.0000.0000.0005.00
is-type level-1
topology ipv6-unicast
segment-routing on
segment-routing global-block 16000 23999
segment-routing node-msd 8
segment-routing prefix 5.5.5.5/32 index 50 no-php-flag
segment-routing prefix 2001:db8:1000::5/128 index 51 no-php-flag
!

View File

@ -0,0 +1,28 @@
log file zebra.log
!
hostname rt5
!
debug zebra kernel
debug zebra packet
debug zebra mpls
!
interface lo
ip address 5.5.5.5/32
ipv6 address 2001:db8:1000::5/128
!
interface eth-rt3-1
ip address 10.0.4.5/24
!
interface eth-rt3-2
ip address 10.0.5.5/24
!
interface eth-rt4
ip address 10.0.6.5/24
!
interface eth-rt6
ip address 10.0.8.5/24
!
ip forwarding
!
line vty
!

View File

@ -0,0 +1,12 @@
log file bgpd.log
!
router bgp 1
bgp router-id 6.6.6.6
neighbor 1.1.1.1 remote-as 1
neighbor 1.1.1.1 update-source lo
!
address-family ipv4 unicast
redistribute static
neighbor 1.1.1.1 next-hop-self
exit-address-family
!

View File

@ -0,0 +1,36 @@
hostname rt6
log file isisd.log
!
debug isis events
debug isis route-events
debug isis spf-events
debug isis sr-events
debug isis lsp-gen
!
interface lo
ip router isis 1
ipv6 router isis 1
isis passive
!
interface eth-rt4
ip router isis 1
ipv6 router isis 1
isis network point-to-point
isis hello-multiplier 3
!
interface eth-rt5
ip router isis 1
ipv6 router isis 1
isis network point-to-point
isis hello-multiplier 3
!
router isis 1
net 49.0000.0000.0000.0006.00
is-type level-1
topology ipv6-unicast
segment-routing on
segment-routing global-block 16000 23999
segment-routing node-msd 8
segment-routing prefix 6.6.6.6/32 index 60
segment-routing prefix 2001:db8:1000::6/128 index 61
!

View File

@ -0,0 +1,21 @@
log file pathd.log
!
hostname rt6
!
segment-routing
traffic-eng
segment-list default
index 10 mpls label 16020
index 20 mpls label 16010
!
segment-list test
index 10 mpls label 16050
index 20 mpls label 16030
index 30 mpls label 16010
!
policy color 1 endpoint 1.1.1.1
name default
binding-sid 6666
!
!
!

View File

@ -0,0 +1,91 @@
{
"6666":{
"inLabel":6666,
"installed":true,
"nexthops":[
{
"type":"SR-TE",
"outLabel":16020,
"outLabelStack":[
16020,
16010
],
"distance":150,
"installed":true,
"nexthop":"10.0.7.4"
}
]
},
"16010": {
"inLabel": 16010,
"installed": true,
"nexthops": [
{
"distance": 150,
"installed": true,
"nexthop": "10.0.7.4",
"outLabel": 16010,
"type": "SR (IS-IS)"
},
{
"distance": 150,
"installed": true,
"nexthop": "10.0.8.5",
"outLabel": 16010,
"type": "SR (IS-IS)"
}
]
},
"16020":{
"inLabel":16020,
"installed":true,
"nexthops":[
{
"type":"SR (IS-IS)",
"outLabel":16020,
"distance":150,
"installed":true,
"nexthop":"10.0.7.4"
}
]
},
"16030":{
"inLabel":16030,
"installed":true,
"nexthops":[
{
"type":"SR (IS-IS)",
"outLabel":16030,
"distance":150,
"installed":true,
"nexthop":"10.0.8.5"
}
]
},
"16040":{
"inLabel":16040,
"installed":true,
"nexthops":[
{
"type":"SR (IS-IS)",
"outLabel":16040,
"distance":150,
"installed":true,
"nexthop":"10.0.7.4"
}
]
},
"16050":{
"inLabel":16050,
"installed":true,
"nexthops":[
{
"type":"SR (IS-IS)",
"outLabel":16050,
"distance":150,
"installed":true,
"nexthop":"10.0.8.5"
}
]
}
}

View File

@ -0,0 +1,74 @@
{
"16010": {
"inLabel": 16010,
"installed": true,
"nexthops": [
{
"distance": 150,
"installed": true,
"nexthop": "10.0.7.4",
"outLabel": 16010,
"type": "SR (IS-IS)"
},
{
"distance": 150,
"installed": true,
"nexthop": "10.0.8.5",
"outLabel": 16010,
"type": "SR (IS-IS)"
}
]
},
"16020":{
"inLabel":16020,
"installed":true,
"nexthops":[
{
"type":"SR (IS-IS)",
"outLabel":16020,
"distance":150,
"installed":true,
"nexthop":"10.0.7.4"
}
]
},
"16030":{
"inLabel":16030,
"installed":true,
"nexthops":[
{
"type":"SR (IS-IS)",
"outLabel":16030,
"distance":150,
"installed":true,
"nexthop":"10.0.8.5"
}
]
},
"16040":{
"inLabel":16040,
"installed":true,
"nexthops":[
{
"type":"SR (IS-IS)",
"outLabel":16040,
"distance":150,
"installed":true,
"nexthop":"10.0.7.4"
}
]
},
"16050":{
"inLabel":16050,
"installed":true,
"nexthops":[
{
"type":"SR (IS-IS)",
"outLabel":16050,
"distance":150,
"installed":true,
"nexthop":"10.0.8.5"
}
]
}
}

View File

@ -0,0 +1,13 @@
{
"frr-pathd:pathd": {
"srte": {
"policy": [
{
"color": 1,
"endpoint": "1.1.1.1",
"is-operational": false
}
]
}
}
}

View File

@ -0,0 +1,19 @@
{
"frr-pathd:pathd": {
"srte": {
"policy": [
{
"color": 1,
"endpoint": "1.1.1.1",
"is-operational": true,
"candidate-path": [
{
"preference": 100,
"is-best-candidate-path": true
}
]
}
]
}
}
}

View File

@ -0,0 +1,19 @@
{
"frr-pathd:pathd": {
"srte": {
"policy": [
{
"color": 1,
"endpoint": "1.1.1.1",
"is-operational": true,
"candidate-path": [
{
"preference": 100,
"is-best-candidate-path": true
}
]
}
]
}
}
}

View File

@ -0,0 +1,23 @@
{
"frr-pathd:pathd": {
"srte": {
"policy": [
{
"color": 1,
"endpoint": "1.1.1.1",
"is-operational": true,
"candidate-path": [
{
"preference": 100,
"is-best-candidate-path": false
},
{
"preference": 200,
"is-best-candidate-path": true
}
]
}
]
}
}
}

View File

@ -0,0 +1,20 @@
{
"6666":{
"inLabel":6666,
"installed":true,
"nexthops":[
{
"type":"SR-TE",
"outLabel":16050,
"outLabelStack":[
16050,
16030,
16010
],
"distance":150,
"installed":true,
"nexthop":"10.0.8.5"
}
]
}
}

View File

@ -0,0 +1,27 @@
log file zebra.log
!
hostname rt6
!
debug zebra kernel
debug zebra packet
debug zebra mpls
!
interface lo
ip address 6.6.6.6/32
ipv6 address 2001:db8:1000::6/128
!
interface eth-rt4
ip address 10.0.7.6/24
!
interface eth-rt5
ip address 10.0.8.6/24
!
interface eth-dst
ip address 10.0.11.1/24
!
ip forwarding
!
ip route 9.9.9.2/32 10.0.11.2
!
line vty
!

View File

@ -0,0 +1,525 @@
#!/usr/bin/env python
#
# test_isis_sr_topo1.py
# Part of NetDEF Topology Tests
#
# Copyright (c) 2019 by
# Network Device Education Foundation, Inc. ("NetDEF")
#
# Permission to use, copy, modify, and/or distribute this software
# for any purpose with or without fee is hereby granted, provided
# that the above copyright notice and this permission notice appear
# in all copies.
#
# THE SOFTWARE IS PROVIDED "AS IS" AND NETDEF DISCLAIMS ALL WARRANTIES
# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NETDEF BE LIABLE FOR
# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY
# DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
# WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
# ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
# OF THIS SOFTWARE.
#
"""
test_isis_sr_te_topo1.py:
+---------+
| |
| RT1 |
| 1.1.1.1 |
| |
+---------+
|eth-sw1
|
|
|
+---------+ | +---------+
| | | | |
| RT2 |eth-sw1 | eth-sw1| RT3 |
| 2.2.2.2 +----------+----------+ 3.3.3.3 |
| | 10.0.1.0/24 | |
+---------+ +---------+
eth-rt4-1| |eth-rt4-2 eth-rt5-1| |eth-rt5-2
| | | |
10.0.2.0/24| |10.0.3.0/24 10.0.4.0/24| |10.0.5.0/24
| | | |
eth-rt2-1| |eth-rt2-2 eth-rt3-1| |eth-rt3-2
+---------+ +---------+
| | | |
| RT4 | 10.0.6.0/24 | RT5 |
| 4.4.4.4 +---------------------+ 5.5.5.5 |
| |eth-rt5 eth-rt4| |
+---------+ +---------+
eth-rt6| |eth-rt6
| |
10.0.7.0/24| |10.0.8.0/24
| +---------+ |
| | | |
| | RT6 | |
+----------+ 6.6.6.6 +-----------+
eth-rt4| |eth-rt5
+---------+
|eth-dst (.1)
|
|10.0.11.0/24
|
|eth-rt6 (.2)
+---------+
| |
| DST |
| 9.9.9.2 |
| |
+---------+
"""
import os
import sys
import pytest
import json
import re
from time import sleep
from functools import partial
# Save the Current Working Directory to find configuration files.
CWD = os.path.dirname(os.path.realpath(__file__))
sys.path.append(os.path.join(CWD, '../'))
# pylint: disable=C0413
# Import topogen and topotest helpers
from lib import topotest
from lib.topogen import Topogen, TopoRouter, get_topogen
from lib.topolog import logger
# Required to instantiate the topology builder class.
from mininet.topo import Topo
class TemplateTopo(Topo):
"Test topology builder"
def build(self, *_args, **_opts):
"Build function"
tgen = get_topogen(self)
#
# Define FRR Routers
#
for router in ['rt1', 'rt2', 'rt3', 'rt4', 'rt5', 'rt6', 'dst']:
tgen.add_router(router)
#
# Define connections
#
switch = tgen.add_switch('s1')
switch.add_link(tgen.gears['rt1'], nodeif="eth-sw1")
switch.add_link(tgen.gears['rt2'], nodeif="eth-sw1")
switch.add_link(tgen.gears['rt3'], nodeif="eth-sw1")
switch = tgen.add_switch('s2')
switch.add_link(tgen.gears['rt2'], nodeif="eth-rt4-1")
switch.add_link(tgen.gears['rt4'], nodeif="eth-rt2-1")
switch = tgen.add_switch('s3')
switch.add_link(tgen.gears['rt2'], nodeif="eth-rt4-2")
switch.add_link(tgen.gears['rt4'], nodeif="eth-rt2-2")
switch = tgen.add_switch('s4')
switch.add_link(tgen.gears['rt3'], nodeif="eth-rt5-1")
switch.add_link(tgen.gears['rt5'], nodeif="eth-rt3-1")
switch = tgen.add_switch('s5')
switch.add_link(tgen.gears['rt3'], nodeif="eth-rt5-2")
switch.add_link(tgen.gears['rt5'], nodeif="eth-rt3-2")
switch = tgen.add_switch('s6')
switch.add_link(tgen.gears['rt4'], nodeif="eth-rt5")
switch.add_link(tgen.gears['rt5'], nodeif="eth-rt4")
switch = tgen.add_switch('s7')
switch.add_link(tgen.gears['rt4'], nodeif="eth-rt6")
switch.add_link(tgen.gears['rt6'], nodeif="eth-rt4")
switch = tgen.add_switch('s8')
switch.add_link(tgen.gears['rt5'], nodeif="eth-rt6")
switch.add_link(tgen.gears['rt6'], nodeif="eth-rt5")
switch = tgen.add_switch('s9')
switch.add_link(tgen.gears['rt6'], nodeif="eth-dst")
switch.add_link(tgen.gears['dst'], nodeif="eth-rt6")
def setup_module(mod):
"Sets up the pytest environment"
tgen = Topogen(TemplateTopo, mod.__name__)
tgen.start_topology()
router_list = tgen.routers()
# For all registered routers, load the zebra configuration file
for rname, router in router_list.iteritems():
router.load_config(
TopoRouter.RD_ZEBRA,
os.path.join(CWD, '{}/zebra.conf'.format(rname))
)
router.load_config(
TopoRouter.RD_ISIS,
os.path.join(CWD, '{}/isisd.conf'.format(rname))
)
router.load_config(
TopoRouter.RD_PATH,
os.path.join(CWD, '{}/pathd.conf'.format(rname))
)
router.load_config(
TopoRouter.RD_BGP,
os.path.join(CWD, '{}/bgpd.conf'.format(rname))
)
tgen.start_router()
def teardown_module(mod):
"Teardown the pytest environment"
tgen = get_topogen()
# This function tears down the whole topology.
tgen.stop_topology()
def setup_testcase(msg):
logger.info(msg)
tgen = get_topogen()
# Skip if previous fatal error condition is raised
if tgen.routers_have_failure():
pytest.skip(tgen.errors)
return tgen
def print_cmd_result(rname, command):
print(get_topogen().gears[rname].vtysh_cmd(command, isjson=False))
def compare_json_test(router, command, reference, exact):
output = router.vtysh_cmd(command, isjson=True)
result = topotest.json_cmp(output, reference)
# Note: topotest.json_cmp() just checks on inclusion of keys.
# For exact matching also compare the other way around.
if not result and exact:
return topotest.json_cmp(reference, output)
else:
return result
def cmp_json_output(rname, command, reference, exact=False):
"Compare router JSON output"
logger.info('Comparing router "%s" "%s" output', rname, command)
tgen = get_topogen()
filename = '{}/{}/{}'.format(CWD, rname, reference)
expected = json.loads(open(filename).read())
# Run test function until we get an result. Wait at most 60 seconds.
test_func = partial(compare_json_test,
tgen.gears[rname], command, expected, exact)
_, diff = topotest.run_and_expect(test_func, None, count=120, wait=0.5)
assertmsg = '"{}" JSON output mismatches the expected result'.format(rname)
assert diff is None, assertmsg
def cmp_json_output_exact(rname, command, reference):
return cmp_json_output(rname, command, reference, True)
def add_candidate_path(rname, endpoint, pref, name, segment_list='default'):
get_topogen().net[rname].cmd(''' \
vtysh -c "conf t" \
-c "segment-routing" \
-c "traffic-eng" \
-c "policy color 1 endpoint ''' + endpoint + '''" \
-c "candidate-path preference ''' + str(pref) + ''' name ''' + name + ''' explicit segment-list ''' + segment_list + '''"''')
def delete_candidate_path(rname, endpoint, pref):
get_topogen().net[rname].cmd(''' \
vtysh -c "conf t" \
-c "segment-routing" \
-c "traffic-eng" \
-c "policy color 1 endpoint ''' + endpoint + '''" \
-c "no candidate-path preference ''' + str(pref) + '''"''')
def add_segment(rname, name, index, label):
get_topogen().net[rname].cmd(''' \
vtysh -c "conf t" \
-c "segment-routing" \
-c "traffic-eng" \
-c "segment-list ''' + name + '''" \
-c "index ''' + str(index) + ''' mpls label ''' + str(label) + '''"''')
def delete_segment(rname, name, index):
get_topogen().net[rname].cmd(''' \
vtysh -c "conf t" \
-c "segment-routing" \
-c "traffic-eng" \
-c "segment-list ''' + name + '''" \
-c "no index ''' + str(index) + '''"''')
def create_sr_policy(rname, endpoint, bsid):
get_topogen().net[rname].cmd(''' \
vtysh -c "conf t" \
-c "segment-routing" \
-c "traffic-eng" \
-c "policy color 1 endpoint ''' + endpoint + '''" \
-c "name default" \
-c "binding-sid ''' + str(bsid) + '''"''')
def delete_sr_policy(rname, endpoint):
get_topogen().net[rname].cmd(''' \
vtysh -c "conf t" \
-c "segment-routing" \
-c "traffic-eng" \
-c "no policy color 1 endpoint ''' + endpoint + '''"''')
def create_prefix_sid(rname, prefix, sid):
get_topogen().net[rname].cmd(''' \
vtysh -c "conf t" \
-c "router isis 1" \
-c "segment-routing prefix ''' + prefix + " index " + str(sid) + '''"''')
def delete_prefix_sid(rname, prefix):
get_topogen().net[rname].cmd(''' \
vtysh -c "conf t" \
-c "router isis 1" \
-c "no segment-routing prefix "''' + prefix)
#
# Step 1
#
# Checking the MPLS table using a single SR Policy and a single Candidate Path
#
def test_srte_init_step1():
setup_testcase("Test (step 1): wait for IS-IS convergence / label distribution")
for rname in ['rt1', 'rt6']:
cmp_json_output(rname,
"show mpls table json",
"step1/show_mpls_table_without_candidate.ref")
def test_srte_add_candidate_check_mpls_table_step1():
setup_testcase("Test (step 1): check MPLS table regarding the added Candidate Path")
for rname, endpoint in [('rt1', '6.6.6.6'), ('rt6', '1.1.1.1')]:
add_candidate_path(rname, endpoint, 100, 'default')
cmp_json_output(rname,
"show mpls table json",
"step1/show_mpls_table_with_candidate.ref")
delete_candidate_path(rname, endpoint, 100)
def test_srte_reinstall_sr_policy_check_mpls_table_step1():
setup_testcase("Test (step 1): check MPLS table after the SR Policy was removed and reinstalled")
for rname, endpoint, bsid in [('rt1', '6.6.6.6', 1111), ('rt6', '1.1.1.1', 6666)]:
add_candidate_path(rname, endpoint, 100, 'default')
delete_sr_policy(rname, endpoint)
cmp_json_output(rname,
"show mpls table json",
"step1/show_mpls_table_without_candidate.ref")
create_sr_policy(rname, endpoint, bsid)
add_candidate_path(rname, endpoint, 100, 'default')
cmp_json_output(rname,
"show mpls table json",
"step1/show_mpls_table_with_candidate.ref")
delete_candidate_path(rname, endpoint, 100)
#
# Step 2
#
# Checking pathd operational data using a single SR Policy and a single Candidate Path
#
def test_srte_bare_policy_step2():
setup_testcase("Test (step 2): bare SR Policy should not be operational")
for rname in ['rt1', 'rt6']:
cmp_json_output_exact(rname,
"show yang operational-data /frr-pathd:pathd pathd",
"step2/show_operational_data.ref")
def test_srte_add_candidate_check_operational_data_step2():
setup_testcase("Test (step 2): add single Candidate Path, SR Policy should be operational")
for rname, endpoint in [('rt1', '6.6.6.6'), ('rt6', '1.1.1.1')]:
add_candidate_path(rname, endpoint, 100, 'default')
cmp_json_output(rname,
"show yang operational-data /frr-pathd:pathd pathd",
"step2/show_operational_data_with_candidate.ref")
def test_srte_config_remove_candidate_check_operational_data_step2():
setup_testcase("Test (step 2): remove single Candidate Path, SR Policy should not be operational anymore")
for rname, endpoint in [('rt1', '6.6.6.6'), ('rt6', '1.1.1.1')]:
delete_candidate_path(rname, endpoint, 100)
cmp_json_output_exact(rname,
"show yang operational-data /frr-pathd:pathd pathd",
"step2/show_operational_data.ref")
#
# Step 3
#
# Testing the Candidate Path selection
#
def test_srte_add_two_candidates_step3():
setup_testcase("Test (step 3): second Candidate Path has higher Priority")
for rname, endpoint in [('rt1', '6.6.6.6'), ('rt6', '1.1.1.1')]:
for pref, cand_name in [('100', 'first'), ('200', 'second')]:
add_candidate_path(rname, endpoint, pref, cand_name)
cmp_json_output(rname,
"show yang operational-data /frr-pathd:pathd pathd",
"step3/show_operational_data_with_two_candidates.ref")
# cleanup
for rname, endpoint in [('rt1', '6.6.6.6'), ('rt6', '1.1.1.1')]:
for pref in ['100', '200']:
delete_candidate_path(rname, endpoint, pref)
def test_srte_add_two_candidates_with_reverse_priority_step3():
setup_testcase("Test (step 3): second Candidate Path has lower Priority")
# Use reversed priorities here
for rname, endpoint in [('rt1', '6.6.6.6'), ('rt6', '1.1.1.1')]:
for pref, cand_name in [('200', 'first'), ('100', 'second')]:
add_candidate_path(rname, endpoint, pref, cand_name)
cmp_json_output(rname,
"show yang operational-data /frr-pathd:pathd pathd",
"step3/show_operational_data_with_two_candidates.ref")
# cleanup
for rname, endpoint in [('rt1', '6.6.6.6'), ('rt6', '1.1.1.1')]:
for pref in ['100', '200']:
delete_candidate_path(rname, endpoint, pref)
def test_srte_remove_best_candidate_step3():
setup_testcase("Test (step 3): delete the Candidate Path with higher priority")
for rname, endpoint in [('rt1', '6.6.6.6'), ('rt6', '1.1.1.1')]:
for pref, cand_name in [('100', 'first'), ('200', 'second')]:
add_candidate_path(rname, endpoint, pref, cand_name)
# Delete candidate with higher priority
for rname, endpoint in [('rt1', '6.6.6.6'), ('rt6', '1.1.1.1')]:
delete_candidate_path(rname, endpoint, 200)
# Candidate with lower priority should get active now
for rname, endpoint in [('rt1', '6.6.6.6'), ('rt6', '1.1.1.1')]:
cmp_json_output(rname,
"show yang operational-data /frr-pathd:pathd pathd",
"step3/show_operational_data_with_single_candidate.ref")
# cleanup
delete_candidate_path(rname, endpoint, 100)
#
# Step 4
#
# Checking MPLS table with a single SR Policy and a Candidate Path with different Segment Lists and other modifications
#
def test_srte_change_segment_list_check_mpls_table_step4():
setup_testcase("Test (step 4): check MPLS table for changed Segment List")
for rname, endpoint in [('rt1', '6.6.6.6'), ('rt6', '1.1.1.1')]:
add_candidate_path(rname, endpoint, 100, 'default')
# now change the segment list name
add_candidate_path(rname, endpoint, 100, 'default', 'test')
cmp_json_output(rname,
"show mpls table json",
"step4/show_mpls_table.ref")
delete_candidate_path(rname, endpoint, 100)
def test_srte_segment_list_add_segment_check_mpls_table_step4():
setup_testcase("Test (step 4): check MPLS table for added (then changed and finally deleted) segment")
add_candidate_path('rt1', '6.6.6.6', 100, 'default', 'test')
# first add a new segment
add_segment('rt1', 'test', 25, 16050)
cmp_json_output('rt1',
"show mpls table json",
"step4/show_mpls_table_add_segment.ref")
# ... then change it ...
add_segment('rt1', 'test', 25, 16030)
cmp_json_output('rt1',
"show mpls table json",
"step4/show_mpls_table_change_segment.ref")
# ... and finally delete it
delete_segment('rt1', 'test', 25)
cmp_json_output('rt1',
"show mpls table json",
"step4/show_mpls_table.ref")
delete_candidate_path('rt1', '6.6.6.6', 100)
#
# Step 5
#
# Checking the nexthop using a single SR Policy and a Candidate Path with configured route-map
#
def test_srte_route_map_with_sr_policy_check_nextop_step5():
setup_testcase("Test (step 5): recursive nexthop learned through BGP neighbour should be aligned with SR Policy from route-map")
# (re-)build the SR Policy two times to ensure that reinstalling still works
for i in [1,2]:
cmp_json_output('rt1',
"show ip route bgp json",
"step5/show_ip_route_bgp_inactive_srte.ref")
delete_sr_policy('rt1', '6.6.6.6')
cmp_json_output('rt1',
"show ip route bgp json",
"step5/show_ip_route_bgp_inactive_srte.ref")
create_sr_policy('rt1', '6.6.6.6', 1111)
cmp_json_output('rt1',
"show ip route bgp json",
"step5/show_ip_route_bgp_inactive_srte.ref")
add_candidate_path('rt1', '6.6.6.6', 100, 'default')
cmp_json_output('rt1',
"show ip route bgp json",
"step5/show_ip_route_bgp_active_srte.ref")
delete_candidate_path('rt1', '6.6.6.6', 100)
def test_srte_route_map_with_sr_policy_reinstall_prefix_sid_check_nextop_step5():
setup_testcase("Test (step 5): remove and re-install prefix SID on fist path element and check SR Policy activity")
# first add a candidate path so the SR Policy is active
add_candidate_path('rt1', '6.6.6.6', 100, 'default')
cmp_json_output('rt1',
"show yang operational-data /frr-pathd:pathd pathd",
"step5/show_operational_data_active.ref")
# delete prefix SID from first element of the configured path and check
# if the SR Policy is inactive since the label can't be resolved anymore
delete_prefix_sid('rt5', "5.5.5.5/32")
cmp_json_output('rt1',
"show yang operational-data /frr-pathd:pathd pathd",
"step5/show_operational_data_inactive.ref")
cmp_json_output('rt1',
"show ip route bgp json",
"step5/show_ip_route_bgp_inactive_srte.ref")
# re-create the prefix SID and check if the SR Policy is active
create_prefix_sid('rt5', "5.5.5.5/32", 50)
cmp_json_output('rt1',
"show yang operational-data /frr-pathd:pathd pathd",
"step5/show_operational_data_active.ref")
cmp_json_output('rt1',
"show ip route bgp json",
"step5/show_ip_route_bgp_active_srte.ref")
# Memory leak test template
def test_memory_leak():
"Run the memory leak test and report results."
tgen = get_topogen()
if not tgen.is_memleak_enabled():
pytest.skip('Memory leak test/report is disabled')
tgen.report_memory_leaks()
if __name__ == '__main__':
args = ["-s"] + sys.argv[1:]
sys.exit(pytest.main(args))

View File

@ -552,6 +552,7 @@ class TopoRouter(TopoGear):
RD_SHARP = 14
RD_BABEL = 15
RD_PBRD = 16
RD_PATH = 17
RD = {
RD_ZEBRA: "zebra",
RD_RIP: "ripd",
@ -569,6 +570,7 @@ class TopoRouter(TopoGear):
RD_SHARP: "sharpd",
RD_BABEL: "babeld",
RD_PBRD: "pbrd",
RD_PATH: 'pathd',
}
def __init__(self, tgen, cls, name, **params):

View File

@ -1096,6 +1096,7 @@ class Router(Node):
"sharpd": 0,
"babeld": 0,
"pbrd": 0,
'pathd': 0
}
self.daemons_options = {"zebra": ""}
self.reportCores = True

View File

@ -626,6 +626,22 @@ end
ctx_keys = []
current_context_lines = []
elif (
line == "exit"
and len(ctx_keys) > 1
and ctx_keys[0].startswith("segment-routing")
):
self.save_contexts(ctx_keys, current_context_lines)
# Start a new context
ctx_keys = ctx_keys[:-1]
current_context_lines = []
log.debug(
"LINE %-50s: popping segment routing sub-context to ctx%-50s",
line,
ctx_keys
)
elif line in ["exit-address-family", "exit", "exit-vnc"]:
# if this exit is for address-family ipv4 unicast, ignore the pop
if main_ctx_key:
@ -637,7 +653,7 @@ end
log.debug(
"LINE %-50s: popping from subcontext to ctx%-50s",
line,
ctx_keys,
ctx_keys
)
elif line in ["exit-vni", "exit-ldp-if"]:
@ -727,6 +743,68 @@ end
)
ctx_keys.append(line)
elif (
line.startswith("traffic-eng")
and len(ctx_keys) == 1
and ctx_keys[0].startswith("segment-routing")
):
# Save old context first
self.save_contexts(ctx_keys, current_context_lines)
current_context_lines = []
log.debug(
"LINE %-50s: entering segment routing sub-context, append to ctx_keys", line
)
ctx_keys.append(line)
elif (
line.startswith("segment-list ")
and len(ctx_keys) == 2
and ctx_keys[0].startswith("segment-routing")
and ctx_keys[1].startswith("traffic-eng")
):
# Save old context first
self.save_contexts(ctx_keys, current_context_lines)
current_context_lines = []
log.debug(
"LINE %-50s: entering segment routing sub-context, append to ctx_keys", line
)
ctx_keys.append(line)
elif (
line.startswith("policy ")
and len(ctx_keys) == 2
and ctx_keys[0].startswith("segment-routing")
and ctx_keys[1].startswith("traffic-eng")
):
# Save old context first
self.save_contexts(ctx_keys, current_context_lines)
current_context_lines = []
log.debug(
"LINE %-50s: entering segment routing sub-context, append to ctx_keys", line
)
ctx_keys.append(line)
elif (
line.startswith("candidate-path ")
and line.endswith(" dynamic")
and len(ctx_keys) == 3
and ctx_keys[0].startswith("segment-routing")
and ctx_keys[1].startswith("traffic-eng")
and ctx_keys[2].startswith("policy")
):
# Save old context first
self.save_contexts(ctx_keys, current_context_lines)
current_context_lines = []
main_ctx_key = copy.deepcopy(ctx_keys)
log.debug(
"LINE %-50s: entering candidate-path sub-context, append to ctx_keys", line
)
ctx_keys.append(line)
else:
# Continuing in an existing context, add non-commented lines to it
current_context_lines.append(line)
@ -1244,6 +1322,9 @@ def compare_context_objects(newconf, running):
# Compare the two Config objects to find the lines that we need to add/del
lines_to_add = []
lines_to_del = []
pollist_to_del = []
seglist_to_del = []
candidates_to_add = []
delete_bgpd = False
# Find contexts that are in newconf but not in running
@ -1326,6 +1407,32 @@ def compare_context_objects(newconf, running):
(running_ctx_keys[:1], None) in lines_to_del):
continue
# Segment routing and traffic engineering never need to be deleted
elif (
len(running_ctx_keys) > 1
and len(running_ctx_keys) < 3
and running_ctx_keys[0].startswith('segment-routing')
):
continue
# Segment lists can only be deleted after we removed all the candidate paths that
# use them, so add them to a separate array that is going to be appended at the end
elif (
len(running_ctx_keys) == 3
and running_ctx_keys[0].startswith('segment-routing')
and running_ctx_keys[2].startswith('segment-list')
):
seglist_to_del.append((running_ctx_keys, None))
# Policies must be deleted after there candidate path, to be sure
# we add them to a separate array that is going to be appended at the end
elif (
len(running_ctx_keys) == 3
and running_ctx_keys[0].startswith('segment-routing')
and running_ctx_keys[2].startswith('policy')
):
pollist_to_del.append((running_ctx_keys, None))
# Non-global context
elif running_ctx_keys and not any(
"address-family" in key for key in running_ctx_keys
@ -1340,6 +1447,14 @@ def compare_context_objects(newconf, running):
for line in running_ctx.lines:
lines_to_del.append((running_ctx_keys, line))
# if we have some policies commands to delete, append them to lines_to_del
if len(pollist_to_del) > 0:
lines_to_del.extend(pollist_to_del)
# if we have some segment list commands to delete, append them to lines_to_del
if len(seglist_to_del) > 0:
lines_to_del.extend(seglist_to_del)
# Find the lines within each context to add
# Find the lines within each context to del
for (newconf_ctx_keys, newconf_ctx) in iteritems(newconf.contexts):
@ -1349,7 +1464,19 @@ def compare_context_objects(newconf, running):
for line in newconf_ctx.lines:
if line not in running_ctx.dlines:
lines_to_add.append((newconf_ctx_keys, line))
# candidate paths can only be added after the policy and segment list,
# so add them to a separate array that is going to be appended at the end
if (
len(newconf_ctx_keys) == 3
and newconf_ctx_keys[0].startswith('segment-routing')
and newconf_ctx_keys[2].startswith('policy ')
and line.startswith('candidate-path ')
):
candidates_to_add.append((newconf_ctx_keys, line))
else:
lines_to_add.append((newconf_ctx_keys, line))
for line in running_ctx.lines:
if line not in newconf_ctx.dlines:
@ -1358,10 +1485,27 @@ def compare_context_objects(newconf, running):
for (newconf_ctx_keys, newconf_ctx) in iteritems(newconf.contexts):
if newconf_ctx_keys not in running.contexts:
lines_to_add.append((newconf_ctx_keys, None))
for line in newconf_ctx.lines:
lines_to_add.append((newconf_ctx_keys, line))
# candidate paths can only be added after the policy and segment list,
# so add them to a separate array that is going to be appended at the end
if (
len(newconf_ctx_keys) == 4
and newconf_ctx_keys[0].startswith('segment-routing')
and newconf_ctx_keys[3].startswith('candidate-path')
):
candidates_to_add.append((newconf_ctx_keys, None))
for line in newconf_ctx.lines:
candidates_to_add.append((newconf_ctx_keys, line))
else:
lines_to_add.append((newconf_ctx_keys, None))
for line in newconf_ctx.lines:
lines_to_add.append((newconf_ctx_keys, line))
# if we have some candidate paths commands to add, append them to lines_to_add
if len(candidates_to_add) > 0:
lines_to_add.extend(candidates_to_add)
(lines_to_add, lines_to_del) = check_for_exit_vrf(lines_to_add, lines_to_del)
(lines_to_add, lines_to_del) = ignore_delete_re_add_lines(
@ -1523,10 +1667,11 @@ if __name__ == "__main__":
"staticd",
"vrrpd",
"ldpd",
"pathd",
]:
log.error(
"Daemon %s is not a valid option for 'show running-config'" % args.daemon
)
msg = "Daemon %s is not a valid option for 'show running-config'" % args.daemon
print(msg)
log.error(msg)
sys.exit(1)
vtysh = Vtysh(args.bindir, args.confdir, args.vty_socket, args.pathspace)
@ -1574,6 +1719,8 @@ if __name__ == "__main__":
else:
running.load_from_show_running(args.daemon)
(lines_to_add, lines_to_del) = compare_context_objects(newconf, running)
lines_to_configure = []

View File

@ -27,7 +27,7 @@ FRR_DEFAULT_PROFILE="@DFLT_NAME@" # traditional / datacenter
# Local Daemon selection may be done by using /etc/frr/daemons.
# See /usr/share/doc/frr/README.Debian.gz for further information.
# Keep zebra first and do not list watchfrr!
DAEMONS="zebra bgpd ripd ripngd ospfd ospf6d isisd babeld pimd ldpd nhrpd eigrpd sharpd pbrd staticd bfdd fabricd vrrpd"
DAEMONS="zebra bgpd ripd ripngd ospfd ospf6d isisd babeld pimd ldpd nhrpd eigrpd sharpd pbrd staticd bfdd fabricd vrrpd pathd"
MAX_INSTANCES=5
RELOAD_SCRIPT="$D_PATH/frr-reload.py"

View File

@ -139,6 +139,7 @@ struct vtysh_client vtysh_client[] = {
{.fd = -1, .name = "staticd", .flag = VTYSH_STATICD, .next = NULL},
{.fd = -1, .name = "bfdd", .flag = VTYSH_BFDD, .next = NULL},
{.fd = -1, .name = "vrrpd", .flag = VTYSH_VRRPD, .next = NULL},
{.fd = -1, .name = "pathd", .flag = VTYSH_PATHD, .next = NULL},
};
/* Searches for client by name, returns index */
@ -538,6 +539,11 @@ static int vtysh_execute_func(const char *line, int pager)
|| saved_node == LDP_IPV6_IFACE_NODE)
&& (tried == 1)) {
vtysh_execute("exit");
} else if ((saved_node == SR_SEGMENT_LIST_NODE
|| saved_node == SR_POLICY_NODE
|| saved_node == SR_CANDIDATE_DYN_NODE)
&& (tried > 0)) {
vtysh_execute("exit");
} else if (tried) {
vtysh_execute("end");
vtysh_execute("configure");
@ -689,6 +695,7 @@ int vtysh_mark_file(const char *filename)
int ret;
vector vline;
int tried = 0;
bool ending;
const struct cmd_element *cmd;
int saved_ret, prev_node;
int lineno = 0;
@ -740,6 +747,12 @@ int vtysh_mark_file(const char *filename)
vty->node = LDP_L2VPN_NODE;
}
break;
case SR_CANDIDATE_DYN_NODE:
if (strncmp(vty_buf_copy, " ", 2)) {
vty_out(vty, " exit\n");
vty->node = SR_POLICY_NODE;
}
break;
default:
break;
}
@ -812,6 +825,23 @@ int vtysh_mark_file(const char *filename)
} else if ((prev_node == BFD_PEER_NODE)
&& (tried == 1)) {
vty_out(vty, "exit\n");
} else if (((prev_node == SEGMENT_ROUTING_NODE)
|| (prev_node == SR_TRAFFIC_ENG_NODE)
|| (prev_node == SR_SEGMENT_LIST_NODE)
|| (prev_node == SR_POLICY_NODE)
|| (prev_node == SR_CANDIDATE_DYN_NODE))
&& (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);
if (ending)
tried--;
while (tried-- > 0)
vty_out(vty, "exit\n");
if (ending)
vty_out(vty, "end\n");
} else if (tried) {
vty_out(vty, "end\n");
}
@ -1219,6 +1249,41 @@ static struct cmd_node pw_node = {
.prompt = "%s(config-pw)# ",
};
static struct cmd_node segment_routing_node = {
.name = "segment-routing",
.node = SEGMENT_ROUTING_NODE,
.parent_node = CONFIG_NODE,
.prompt = "%s(config-sr)# ",
};
static struct cmd_node sr_traffic_eng_node = {
.name = "sr traffic-eng",
.node = SR_TRAFFIC_ENG_NODE,
.parent_node = SEGMENT_ROUTING_NODE,
.prompt = "%s(config-sr-te)# ",
};
static struct cmd_node srte_segment_list_node = {
.name = "srte segment-list",
.node = SR_SEGMENT_LIST_NODE,
.parent_node = SR_TRAFFIC_ENG_NODE,
.prompt = "%s(config-sr-te-segment-list)# ",
};
static struct cmd_node srte_policy_node = {
.name = "srte policy",
.node = SR_POLICY_NODE,
.parent_node = SR_TRAFFIC_ENG_NODE,
.prompt = "%s(config-sr-te-policy)# ",
};
static struct cmd_node srte_candidate_dyn_node = {
.name = "srte candidate-dyn",
.node = SR_CANDIDATE_DYN_NODE,
.parent_node = SR_POLICY_NODE,
.prompt = "%s(config-sr-te-candidate)# ",
};
static struct cmd_node vrf_node = {
.name = "vrf",
.node = VRF_NODE,
@ -1974,6 +2039,60 @@ DEFUNSH(VTYSH_FABRICD, router_openfabric, router_openfabric_cmd, "router openfab
}
#endif /* HAVE_FABRICD */
#if defined(HAVE_PATHD)
DEFUNSH(VTYSH_PATHD, segment_routing, segment_routing_cmd,
"segment-routing",
"Configure segment routing\n")
{
vty->node = SEGMENT_ROUTING_NODE;
return CMD_SUCCESS;
}
DEFUNSH(VTYSH_PATHD, sr_traffic_eng, sr_traffic_eng_cmd,
"traffic-eng",
"Configure SR traffic engineering\n")
{
vty->node = SR_TRAFFIC_ENG_NODE;
return CMD_SUCCESS;
}
DEFUNSH(VTYSH_PATHD, srte_segment_list, srte_segment_list_cmd,
"segment-list WORD$name",
"Segment List\n"
"Segment List Name\n")
{
vty->node = SR_SEGMENT_LIST_NODE;
return CMD_SUCCESS;
}
DEFUNSH(VTYSH_PATHD, srte_policy, srte_policy_cmd,
"policy color (0-4294967295) endpoint <A.B.C.D|X:X::X:X>",
"Segment Routing Policy\n"
"SR Policy color\n"
"SR Policy color value\n"
"SR Policy endpoint\n"
"SR Policy endpoint IPv4 address\n"
"SR Policy endpoint IPv6 address\n")
{
vty->node = SR_POLICY_NODE;
return CMD_SUCCESS;
}
DEFUNSH(VTYSH_PATHD, srte_policy_candidate_dyn_path,
srte_policy_candidate_dyn_path_cmd,
"candidate-path preference (0-4294967295) name WORD dynamic",
"Segment Routing Policy Candidate Path\n"
"Segment Routing Policy Candidate Path Preference\n"
"Administrative Preference\n"
"Segment Routing Policy Candidate Path Name\n"
"Symbolic Name\n"
"Dynamic Path\n")
{
vty->node = SR_CANDIDATE_DYN_NODE;
return CMD_SUCCESS;
}
#endif /* HAVE_PATHD */
DEFUNSH(VTYSH_RMAP, vtysh_route_map, vtysh_route_map_cmd,
"route-map WORD <deny|permit> (1-65535)",
"Create route-map or enter route-map command mode\n"
@ -2347,6 +2466,18 @@ DEFUNSH(VTYSH_KEYS, vtysh_quit_keys, vtysh_quit_keys_cmd, "quit",
return vtysh_exit_keys(self, vty, argc, argv);
}
DEFUNSH(VTYSH_PATHD, vtysh_exit_pathd, vtysh_exit_pathd_cmd, "exit",
"Exit current mode and down to previous mode\n")
{
return vtysh_exit(vty);
}
DEFUNSH(VTYSH_PATHD, vtysh_quit_pathd, vtysh_quit_pathd_cmd, "quit",
"Exit current mode and down to previous mode\n")
{
return vtysh_exit_pathd(self, vty, argc, argv);
}
DEFUNSH(VTYSH_ALL, vtysh_exit_line_vty, vtysh_exit_line_vty_cmd, "exit",
"Exit current mode and down to previous mode\n")
{
@ -4144,6 +4275,37 @@ void vtysh_init_vty(void)
install_element(BFD_PROFILE_NODE, &vtysh_end_all_cmd);
#endif /* HAVE_BFDD */
#if defined(HAVE_PATHD)
install_node(&segment_routing_node);
install_node(&sr_traffic_eng_node);
install_node(&srte_segment_list_node);
install_node(&srte_policy_node);
install_node(&srte_candidate_dyn_node);
install_element(SEGMENT_ROUTING_NODE, &vtysh_exit_pathd_cmd);
install_element(SEGMENT_ROUTING_NODE, &vtysh_quit_pathd_cmd);
install_element(SR_TRAFFIC_ENG_NODE, &vtysh_exit_pathd_cmd);
install_element(SR_TRAFFIC_ENG_NODE, &vtysh_quit_pathd_cmd);
install_element(SR_SEGMENT_LIST_NODE, &vtysh_exit_pathd_cmd);
install_element(SR_SEGMENT_LIST_NODE, &vtysh_quit_pathd_cmd);
install_element(SR_POLICY_NODE, &vtysh_exit_pathd_cmd);
install_element(SR_POLICY_NODE, &vtysh_quit_pathd_cmd);
install_element(SR_CANDIDATE_DYN_NODE, &vtysh_exit_pathd_cmd);
install_element(SR_CANDIDATE_DYN_NODE, &vtysh_quit_pathd_cmd);
install_element(SEGMENT_ROUTING_NODE, &vtysh_end_all_cmd);
install_element(SR_TRAFFIC_ENG_NODE, &vtysh_end_all_cmd);
install_element(SR_SEGMENT_LIST_NODE, &vtysh_end_all_cmd);
install_element(SR_POLICY_NODE, &vtysh_end_all_cmd);
install_element(SR_CANDIDATE_DYN_NODE, &vtysh_end_all_cmd);
install_element(CONFIG_NODE, &segment_routing_cmd);
install_element(SEGMENT_ROUTING_NODE, &sr_traffic_eng_cmd);
install_element(SR_TRAFFIC_ENG_NODE, &srte_segment_list_cmd);
install_element(SR_TRAFFIC_ENG_NODE, &srte_policy_cmd);
install_element(SR_POLICY_NODE, &srte_policy_candidate_dyn_path_cmd);
#endif /* HAVE_PATHD */
/* keychain */
install_node(&keychain_node);
install_element(CONFIG_NODE, &key_chain_cmd);

View File

@ -43,6 +43,7 @@ DECLARE_MGROUP(MVTYSH)
#define VTYSH_BFDD 0x10000
#define VTYSH_FABRICD 0x20000
#define VTYSH_VRRPD 0x40000
#define VTYSH_PATHD 0x80000
#define VTYSH_WAS_ACTIVE (-2)
@ -51,7 +52,7 @@ DECLARE_MGROUP(MVTYSH)
/* watchfrr is not in ALL since library CLI functions should not be
* run on it (logging & co. should stay in a fixed/frozen config, and
* things like prefix lists are not even initialised) */
#define VTYSH_ALL VTYSH_ZEBRA|VTYSH_RIPD|VTYSH_RIPNGD|VTYSH_OSPFD|VTYSH_OSPF6D|VTYSH_LDPD|VTYSH_BGPD|VTYSH_ISISD|VTYSH_PIMD|VTYSH_NHRPD|VTYSH_EIGRPD|VTYSH_BABELD|VTYSH_SHARPD|VTYSH_PBRD|VTYSH_STATICD|VTYSH_BFDD|VTYSH_FABRICD|VTYSH_VRRPD
#define VTYSH_ALL VTYSH_ZEBRA|VTYSH_RIPD|VTYSH_RIPNGD|VTYSH_OSPFD|VTYSH_OSPF6D|VTYSH_LDPD|VTYSH_BGPD|VTYSH_ISISD|VTYSH_PIMD|VTYSH_NHRPD|VTYSH_EIGRPD|VTYSH_BABELD|VTYSH_SHARPD|VTYSH_PBRD|VTYSH_STATICD|VTYSH_BFDD|VTYSH_FABRICD|VTYSH_VRRPD|VTYSH_PATHD
#define VTYSH_ACL VTYSH_BFDD|VTYSH_BABELD|VTYSH_BGPD|VTYSH_EIGRPD|VTYSH_ISISD|VTYSH_FABRICD|VTYSH_LDPD|VTYSH_NHRPD|VTYSH_OSPF6D|VTYSH_OSPFD|VTYSH_PBRD|VTYSH_PIMD|VTYSH_RIPD|VTYSH_RIPNGD|VTYSH_VRRPD|VTYSH_ZEBRA
#define VTYSH_RMAP VTYSH_ZEBRA|VTYSH_RIPD|VTYSH_RIPNGD|VTYSH_OSPFD|VTYSH_OSPF6D|VTYSH_BGPD|VTYSH_ISISD|VTYSH_PIMD|VTYSH_EIGRPD|VTYSH_FABRICD
#define VTYSH_INTERFACE VTYSH_ZEBRA|VTYSH_RIPD|VTYSH_RIPNGD|VTYSH_OSPFD|VTYSH_OSPF6D|VTYSH_ISISD|VTYSH_PIMD|VTYSH_NHRPD|VTYSH_EIGRPD|VTYSH_BABELD|VTYSH_PBRD|VTYSH_FABRICD|VTYSH_VRRPD

480
yang/frr-pathd.yang Normal file
View File

@ -0,0 +1,480 @@
module frr-pathd {
yang-version 1.1;
namespace "http://frrouting.org/yang/pathd";
prefix frr-pathd;
import ietf-inet-types {
prefix inet;
}
import ietf-yang-types {
prefix yang;
}
import ietf-routing-types {
prefix rt-types;
}
import frr-interface {
prefix frr-interface;
}
organization
"Free Range Routing";
contact
"FRR Users List: <mailto:frog@lists.frrouting.org>
FRR Development List: <mailto:dev@lists.frrouting.org>";
description
"This module defines a model for managing FRR pathd daemon.";
revision 2018-11-06 {
description
"Initial revision.";
}
typedef protocol-origin-type {
description
"Indication for the protocol origin of an object.";
type enumeration {
enum pcep {
value 1;
description "The object was created through PCEP";
}
enum bgp {
value 2;
description "The object was created through GBP";
}
enum local {
value 3;
description "The object was created through CLI, Yang model via Netconf, gRPC, etc";
}
}
}
typedef originator-type {
type string {
length "1..64";
}
description
"Identifier of the originator of an object, could be 'config', '1.1.1.1:4189' or '2001:db8:85a3::8a2e:370:7334:4189'";
}
container pathd {
container srte {
list segment-list {
key "name";
description "Segment-list properties";
leaf name {
type string {
length "1..64";
}
description "Segment-list name";
}
leaf protocol-origin {
type protocol-origin-type;
mandatory true;
description
"Indication for the protocol origin of the segment list.";
}
leaf originator {
type originator-type;
mandatory true;
description "Originator of the segment list";
}
list segment {
key "index";
description "Configure Segment/hop at the index";
leaf index {
type uint32;
description "Segment index";
}
leaf sid-value {
type rt-types:mpls-label;
mandatory true;
description "MPLS label value";
}
container nai {
presence "The segement has a Node or Adjacency Identifier";
leaf type {
description "NAI type";
mandatory true;
type enumeration {
enum ipv4_node {
value 1;
description "IPv4 node identifier";
}
enum ipv6_node {
value 2;
description "IPv6 node identifier";
}
enum ipv4_adjacency {
value 3;
description "IPv4 adjacency";
}
enum ipv6_adjacency {
value 4;
description "IPv6 adjacency";
}
enum ipv4_unnumbered_adjacency {
value 5;
description "IPv4 unnumbered adjacency";
}
}
}
leaf local-address {
type inet:ip-address;
mandatory true;
}
leaf local-interface {
type uint32;
mandatory true;
when "../type = 'ipv4_unnumbered_adjacency'";
}
leaf remote-address {
type inet:ip-address;
mandatory true;
when "../type = 'ipv4_adjacency' or ../type = 'ipv6_adjacency' or ../type = 'ipv4_unnumbered_adjacency'";
}
leaf remote-interface {
type uint32;
mandatory true;
when "../type = 'ipv4_unnumbered_adjacency'";
}
}
}
}
list policy {
key "color endpoint";
unique "name";
leaf color {
type uint32;
description
"Color of the SR Policy.";
}
leaf endpoint {
type inet:ip-address;
description
"Indication for the endpoint of the SR Policy.";
}
leaf name {
type string {
length "1..64";
}
description
"Name of the SR Policy.";
}
leaf binding-sid {
type rt-types:mpls-label;
description
"BSID of the SR Policy.";
}
leaf is-operational {
type boolean;
config false;
description
"True if a valid candidate path of this policy is operational in zebra, False otherwise";
}
list candidate-path {
unique "name";
description
"List of Candidate Paths of the SR Policy.";
key "preference";
leaf preference {
type uint32;
description
"Administrative preference.";
}
leaf name {
type string {
length "1..64";
}
mandatory true;
description
"Symbolic Name of the Candidate Path.";
}
leaf is-best-candidate-path {
type boolean;
config false;
description
"True if the candidate path is the best candidate path, False otherwise";
}
leaf protocol-origin {
type protocol-origin-type;
mandatory true;
description
"Indication for the protocol origin of the Candidate Path.";
}
leaf originator {
type originator-type;
mandatory true;
description "Originator of the candidate path";
}
leaf discriminator {
type uint32;
config false;
description "Candidate path distinguisher";
}
leaf type {
description
"Type of the Candidate Path.";
mandatory true;
type enumeration {
enum explicit {
value 1;
}
enum dynamic {
value 2;
}
}
}
leaf segment-list-name {
type leafref {
path ../../../segment-list/name;
}
description
"The name of the Segment List to use as LSP.";
}
container constraints {
when "../type = 'dynamic'";
description
"Generic dynamic path constraints";
container bandwidth {
presence "If the candidate has a bandwidth constraint";
description
"The bandwidth needed by the candidate path.";
leaf required {
type boolean;
default "true";
description
"If the bandwidth limitation is a requirement or only a suggestion";
}
leaf value {
mandatory true;
type decimal64 {
fraction-digits 6;
}
}
}
container affinity {
description
"Affinity let you configure how the links should be used when calculating a path.";
leaf exclude-any {
type uint32;
description
"A 32-bit vector representing a set of attribute filters which renders a link unacceptable.";
}
leaf include-any {
type uint32;
description
"A 32-bit vector representing a set of attribute filters which renders a link acceptable. A null set (all bits set to zero) automatically passes.";
}
leaf include-all {
type uint32;
description
"A 32-bit vector representing a set of attribute filters which must be present for a link to be acceptable. A null set (all bits set to zero) automatically passes.";
}
}
list metrics {
key "type";
leaf type {
description
"Type of the metric.";
type enumeration {
enum igp {
value 1;
description "IGP metric";
}
enum te {
value 2;
description "TE metric";
}
enum hc {
value 3;
description "Hop Counts";
}
enum abc {
value 4;
description "Aggregate bandwidth consumption";
}
enum lmll {
value 5;
description "Load of the most loaded link";
}
enum cigp {
value 6;
description "Cumulative IGP cost";
}
enum cte {
value 7;
description "Cumulative TE cost";
}
enum pigp {
value 8;
description "P2MP IGP metric";
}
enum pte {
value 9;
description "P2MP TE metric";
}
enum phc {
value 10;
description "P2MP hop count metric";
}
enum msd {
value 11;
description "Segment-ID (SID) Depth";
}
enum pd {
value 12;
description "Path Delay metric";
}
enum pdv {
value 13;
description "Path Delay Variation metric";
}
enum pl {
value 14;
description "Path Loss metric";
}
enum ppd {
value 15;
description "P2MP Path Delay metric";
}
enum ppdv {
value 16;
description "P2MP Path Delay variation metric";
}
enum ppl {
value 17;
description "P2MP Path Loss metric";
}
enum nap {
value 18;
description "Number of adaptations on a path";
}
enum nlp {
value 19;
description "Number of layers on a path";
}
enum dc {
value 20;
description "Domain Count metric";
}
enum bnc {
value 21;
description "Border Node Count metric";
}
}
}
leaf required {
type boolean;
default "true";
description
"If the metric is a requirement, or if it is only a suggestion";
}
leaf is-bound {
type boolean;
description
"Defines if the value is a bound (a maximum) for the path metric that must not be exceeded.";
}
leaf is-computed {
type boolean;
description
"Defines if the value has been generated by the originator of the path.";
}
leaf value {
mandatory true;
type decimal64 {
fraction-digits 6;
}
}
}
container objective-function {
presence "If the candidate has an objective function constraint";
description
"Define objective function constraint as a list of prefered functions";
leaf required {
type boolean;
default "true";
description
"If an objective function is a requirement, or if it is only a suggestion";
}
leaf type {
description
"Type of objective function.";
mandatory true;
type enumeration {
enum mcp {
value 1;
description "Minimum Cost Path";
}
enum mlp {
value 2;
description "Minimum Load Path";
}
enum mbp {
value 3;
description "Maximum residual Bandwidth Path";
}
enum mbc {
value 4;
description "Minimize aggregate Bandwidth Consumption";
}
enum mll {
value 5;
description "Minimize the Load of the most loaded Link";
}
enum mcc {
value 6;
description "Minimize the Cumulative Cost of a set of paths";
}
enum spt {
value 7;
description "Shortest Path Tree";
}
enum mct {
value 8;
description "Minimum Cost Tree";
}
enum mplp {
value 9;
description "Minimum Packet Loss Path";
}
enum mup {
value 10;
description "Maximum Under-Utilized Path";
}
enum mrup {
value 11;
description "Maximum Reserved Under-Utilized Path";
}
enum mtd {
value 12;
description "Minimize the number of Transit Domains";
}
enum mbn {
value 13;
description "Minimize the number of Border Nodes";
}
enum mctd {
value 14;
description "Minimize the number of Common Transit Domains";
}
enum msl {
value 15;
description "Minimize the number of Shared Links";
}
enum mss {
value 16;
description "Minimize the number of Shared SRLGs";
}
enum msn {
value 17;
description "Minimize the number of Shared Nodes";
}
}
}
}
}
}
}
}
}
}

View File

@ -82,3 +82,7 @@ dist_yangmodels_DATA += yang/frr-bgp-bmp.yang
dist_yangmodels_DATA += yang/frr-bgp-types.yang
dist_yangmodels_DATA += yang/frr-bgp.yang
endif
if PATHD
dist_yangmodels_DATA += yang/frr-pathd.yang
endif