mirror of
https://git.proxmox.com/git/mirror_frr
synced 2025-08-04 20:18:54 +00:00
Merge pull request #7707 from opensourcerouting/isisd-rlfa
isisd, ldpd: add Remote LFA support
This commit is contained in:
commit
4683138cda
@ -204,6 +204,12 @@ ISIS Fast-Reroute
|
||||
|
||||
Disable load sharing across multiple LFA backups.
|
||||
|
||||
.. index:: fast-reroute remote-lfa prefix-list WORD [level-1 | level-2]
|
||||
.. clicmd:: [no] fast-reroute remote-lfa prefix-list [WORD] [level-1 | level-2]
|
||||
|
||||
Configure a prefix-list to select eligible PQ nodes (valid for all protected
|
||||
interfaces).
|
||||
|
||||
.. _isis-region:
|
||||
|
||||
ISIS region
|
||||
@ -400,6 +406,18 @@ ISIS interface
|
||||
|
||||
Enable per-prefix TI-LFA fast reroute link or node protection.
|
||||
|
||||
.. index:: isis fast-reroute remote-lfa tunnel mpls-ldp [level-1 | level-2]
|
||||
.. clicmd:: [no] isis fast-reroute remote-lfa tunnel mpls-ldp [level-1 | level-2]
|
||||
|
||||
Enable per-prefix Remote LFA fast reroute link protection. Note that other
|
||||
routers in the network need to be configured to accept LDP targeted hello
|
||||
messages in order for RLFA to work.
|
||||
|
||||
.. index:: isis fast-reroute remote-lfa maximum-metric (1-16777215) [level-1 | level-2]
|
||||
.. clicmd:: [no] isis fast-reroute remote-lfa maximum-metric (1-16777215) [level-1 | level-2]
|
||||
|
||||
Limit Remote LFA PQ node selection within the specified metric.
|
||||
|
||||
.. _showing-isis-information:
|
||||
|
||||
Showing ISIS information
|
||||
|
@ -142,6 +142,8 @@ struct isis_circuit {
|
||||
struct bfd_info *bfd_info;
|
||||
struct ldp_sync_info *ldp_sync_info;
|
||||
bool lfa_protection[ISIS_LEVELS];
|
||||
bool rlfa_protection[ISIS_LEVELS];
|
||||
uint32_t rlfa_max_metric[ISIS_LEVELS];
|
||||
struct hash *lfa_excluded_ifaces[ISIS_LEVELS];
|
||||
bool tilfa_protection[ISIS_LEVELS];
|
||||
bool tilfa_node_protection[ISIS_LEVELS];
|
||||
|
185
isisd/isis_cli.c
185
isisd/isis_cli.c
@ -1915,22 +1915,22 @@ DEFPY_YANG (isis_frr_lfa_load_sharing,
|
||||
if (no) {
|
||||
nb_cli_enqueue_change(
|
||||
vty, "./fast-reroute/level-1/lfa/load-sharing",
|
||||
NB_OP_DESTROY, "true");
|
||||
NB_OP_MODIFY, "true");
|
||||
} else {
|
||||
nb_cli_enqueue_change(
|
||||
vty, "./fast-reroute/level-1/lfa/load-sharing",
|
||||
NB_OP_CREATE, "false");
|
||||
NB_OP_MODIFY, "false");
|
||||
}
|
||||
}
|
||||
if (!level || strmatch(level, "level-2")) {
|
||||
if (no) {
|
||||
nb_cli_enqueue_change(
|
||||
vty, "./fast-reroute/level-2/lfa/load-sharing",
|
||||
NB_OP_DESTROY, "true");
|
||||
NB_OP_MODIFY, "true");
|
||||
} else {
|
||||
nb_cli_enqueue_change(
|
||||
vty, "./fast-reroute/level-2/lfa/load-sharing",
|
||||
NB_OP_CREATE, "false");
|
||||
NB_OP_MODIFY, "false");
|
||||
}
|
||||
}
|
||||
|
||||
@ -1947,6 +1947,62 @@ void cli_show_isis_frr_lfa_load_sharing(struct vty *vty, struct lyd_node *dnode,
|
||||
dnode->parent->parent->schema->name);
|
||||
}
|
||||
|
||||
/*
|
||||
* XPath: /frr-isisd:isis/instance/fast-reroute/level-{1,2}/remote-lfa/prefix-list
|
||||
*/
|
||||
DEFPY_YANG (isis_frr_remote_lfa_plist,
|
||||
isis_frr_remote_lfa_plist_cmd,
|
||||
"fast-reroute remote-lfa prefix-list WORD$plist [<level-1|level-2>$level]",
|
||||
"Configure Fast ReRoute\n"
|
||||
"Enable remote LFA related configuration\n"
|
||||
"Filter PQ node router ID based on prefix list\n"
|
||||
"Prefix-list name\n"
|
||||
"Enable router ID filtering for level-1 only\n"
|
||||
"Enable router ID filtering for level-2 only\n")
|
||||
{
|
||||
if (!level || strmatch(level, "level-1"))
|
||||
nb_cli_enqueue_change(
|
||||
vty, "./fast-reroute/level-1/remote-lfa/prefix-list",
|
||||
NB_OP_MODIFY, plist);
|
||||
if (!level || strmatch(level, "level-2"))
|
||||
nb_cli_enqueue_change(
|
||||
vty, "./fast-reroute/level-2/remote-lfa/prefix-list",
|
||||
NB_OP_MODIFY, plist);
|
||||
|
||||
return nb_cli_apply_changes(vty, NULL);
|
||||
}
|
||||
|
||||
DEFPY_YANG (no_isis_frr_remote_lfa_plist,
|
||||
no_isis_frr_remote_lfa_plist_cmd,
|
||||
"no fast-reroute remote-lfa prefix-list [WORD] [<level-1|level-2>$level]",
|
||||
NO_STR
|
||||
"Configure Fast ReRoute\n"
|
||||
"Enable remote LFA related configuration\n"
|
||||
"Filter PQ node router ID based on prefix list\n"
|
||||
"Prefix-list name\n"
|
||||
"Enable router ID filtering for level-1 only\n"
|
||||
"Enable router ID filtering for level-2 only\n")
|
||||
{
|
||||
if (!level || strmatch(level, "level-1"))
|
||||
nb_cli_enqueue_change(
|
||||
vty, "./fast-reroute/level-1/remote-lfa/prefix-list",
|
||||
NB_OP_DESTROY, NULL);
|
||||
if (!level || strmatch(level, "level-2"))
|
||||
nb_cli_enqueue_change(
|
||||
vty, "./fast-reroute/level-2/remote-lfa/prefix-list",
|
||||
NB_OP_DESTROY, NULL);
|
||||
|
||||
return nb_cli_apply_changes(vty, NULL);
|
||||
}
|
||||
|
||||
void cli_show_isis_frr_remote_lfa_plist(struct vty *vty, struct lyd_node *dnode,
|
||||
bool show_defaults)
|
||||
{
|
||||
vty_out(vty, " fast-reroute remote-lfa prefix-list %s %s\n",
|
||||
yang_dnode_get_string(dnode, NULL),
|
||||
dnode->parent->parent->schema->name);
|
||||
}
|
||||
|
||||
/*
|
||||
* XPath: /frr-interface:lib/interface/frr-isisd:isis/passive
|
||||
*/
|
||||
@ -2630,6 +2686,25 @@ void cli_show_ip_isis_frr(struct vty *vty, struct lyd_node *dnode,
|
||||
}
|
||||
}
|
||||
|
||||
/* Remote LFA */
|
||||
l1_enabled = yang_dnode_get_bool(dnode, "./level-1/remote-lfa/enable");
|
||||
l2_enabled = yang_dnode_get_bool(dnode, "./level-2/remote-lfa/enable");
|
||||
|
||||
if (l1_enabled || l2_enabled) {
|
||||
if (l1_enabled == l2_enabled) {
|
||||
vty_out(vty,
|
||||
" isis fast-reroute remote-lfa tunnel mpls-ldp\n");
|
||||
vty_out(vty, "\n");
|
||||
} else {
|
||||
if (l1_enabled)
|
||||
vty_out(vty,
|
||||
" isis fast-reroute remote-lfa tunnel mpls-ldp level-1\n");
|
||||
if (l2_enabled)
|
||||
vty_out(vty,
|
||||
" isis fast-reroute remote-lfa tunnel mpls-ldp level-2\n");
|
||||
}
|
||||
}
|
||||
|
||||
/* TI-LFA */
|
||||
l1_enabled = yang_dnode_get_bool(dnode, "./level-1/ti-lfa/enable");
|
||||
l2_enabled = yang_dnode_get_bool(dnode, "./level-2/ti-lfa/enable");
|
||||
@ -2760,6 +2835,104 @@ void cli_show_frr_lfa_exclude_interface(struct vty *vty, struct lyd_node *dnode,
|
||||
yang_dnode_get_string(dnode, NULL));
|
||||
}
|
||||
|
||||
/*
|
||||
* XPath:
|
||||
* /frr-interface:lib/interface/frr-isisd:isis/fast-reroute/level-{1,2}/remote-lfa/enable
|
||||
*/
|
||||
DEFPY(isis_remote_lfa, isis_remote_lfa_cmd,
|
||||
"[no] isis fast-reroute remote-lfa tunnel mpls-ldp [level-1|level-2]$level",
|
||||
NO_STR
|
||||
"IS-IS routing protocol\n"
|
||||
"Interface IP Fast-reroute configuration\n"
|
||||
"Enable remote LFA computation\n"
|
||||
"Enable remote LFA computation using tunnels\n"
|
||||
"Use MPLS LDP tunnel to reach the remote LFA node\n"
|
||||
"Enable LFA computation for Level 1 only\n"
|
||||
"Enable LFA computation for Level 2 only\n")
|
||||
{
|
||||
if (!level || strmatch(level, "level-1")) {
|
||||
if (no) {
|
||||
nb_cli_enqueue_change(
|
||||
vty,
|
||||
"./frr-isisd:isis/fast-reroute/level-1/remote-lfa/enable",
|
||||
NB_OP_MODIFY, "false");
|
||||
} else {
|
||||
nb_cli_enqueue_change(
|
||||
vty,
|
||||
"./frr-isisd:isis/fast-reroute/level-1/remote-lfa/enable",
|
||||
NB_OP_MODIFY, "true");
|
||||
}
|
||||
}
|
||||
if (!level || strmatch(level, "level-2")) {
|
||||
if (no) {
|
||||
nb_cli_enqueue_change(
|
||||
vty,
|
||||
"./frr-isisd:isis/fast-reroute/level-2/remote-lfa/enable",
|
||||
NB_OP_MODIFY, "false");
|
||||
} else {
|
||||
nb_cli_enqueue_change(
|
||||
vty,
|
||||
"./frr-isisd:isis/fast-reroute/level-2/remote-lfa/enable",
|
||||
NB_OP_MODIFY, "true");
|
||||
}
|
||||
}
|
||||
|
||||
return nb_cli_apply_changes(vty, NULL);
|
||||
}
|
||||
|
||||
/*
|
||||
* XPath:
|
||||
* /frr-interface:lib/interface/frr-isisd:isis/fast-reroute/level-{1,2}/remote-lfa/maximum-metric
|
||||
*/
|
||||
DEFPY(isis_remote_lfa_max_metric, isis_remote_lfa_max_metric_cmd,
|
||||
"[no] isis fast-reroute remote-lfa maximum-metric (1-16777215)$metric [level-1|level-2]$level",
|
||||
NO_STR
|
||||
"IS-IS routing protocol\n"
|
||||
"Interface IP Fast-reroute configuration\n"
|
||||
"Enable remote LFA computation\n"
|
||||
"Limit remote LFA node selection within the metric\n"
|
||||
"Value of the metric\n"
|
||||
"Enable LFA computation for Level 1 only\n"
|
||||
"Enable LFA computation for Level 2 only\n")
|
||||
{
|
||||
if (!level || strmatch(level, "level-1")) {
|
||||
if (no) {
|
||||
nb_cli_enqueue_change(
|
||||
vty,
|
||||
"./frr-isisd:isis/fast-reroute/level-1/remote-lfa/maximum-metric",
|
||||
NB_OP_DESTROY, NULL);
|
||||
} else {
|
||||
nb_cli_enqueue_change(
|
||||
vty,
|
||||
"./frr-isisd:isis/fast-reroute/level-1/remote-lfa/maximum-metric",
|
||||
NB_OP_MODIFY, metric_str);
|
||||
}
|
||||
}
|
||||
if (!level || strmatch(level, "level-2")) {
|
||||
if (no) {
|
||||
nb_cli_enqueue_change(
|
||||
vty,
|
||||
"./frr-isisd:isis/fast-reroute/level-2/remote-lfa/maximum-metric",
|
||||
NB_OP_DESTROY, NULL);
|
||||
} else {
|
||||
nb_cli_enqueue_change(
|
||||
vty,
|
||||
"./frr-isisd:isis/fast-reroute/level-2/remote-lfa/maximum-metric",
|
||||
NB_OP_MODIFY, metric_str);
|
||||
}
|
||||
}
|
||||
|
||||
return nb_cli_apply_changes(vty, NULL);
|
||||
}
|
||||
|
||||
void cli_show_frr_remote_lfa_max_metric(struct vty *vty, struct lyd_node *dnode,
|
||||
bool show_defaults)
|
||||
{
|
||||
vty_out(vty, " isis fast-reroute remote-lfa maximum-metric %s %s\n",
|
||||
yang_dnode_get_string(dnode, NULL),
|
||||
dnode->parent->parent->schema->name);
|
||||
}
|
||||
|
||||
/*
|
||||
* XPath: /frr-interface:lib/interface/frr-isisd:isis/fast-reroute/level-{1,2}/ti-lfa/enable
|
||||
*/
|
||||
@ -3085,6 +3258,8 @@ void isis_cli_init(void)
|
||||
install_element(ISIS_NODE, &isis_frr_lfa_priority_limit_cmd);
|
||||
install_element(ISIS_NODE, &isis_frr_lfa_tiebreaker_cmd);
|
||||
install_element(ISIS_NODE, &isis_frr_lfa_load_sharing_cmd);
|
||||
install_element(ISIS_NODE, &isis_frr_remote_lfa_plist_cmd);
|
||||
install_element(ISIS_NODE, &no_isis_frr_remote_lfa_plist_cmd);
|
||||
|
||||
install_element(INTERFACE_NODE, &isis_passive_cmd);
|
||||
|
||||
@ -3122,6 +3297,8 @@ void isis_cli_init(void)
|
||||
|
||||
install_element(INTERFACE_NODE, &isis_lfa_cmd);
|
||||
install_element(INTERFACE_NODE, &isis_lfa_exclude_interface_cmd);
|
||||
install_element(INTERFACE_NODE, &isis_remote_lfa_cmd);
|
||||
install_element(INTERFACE_NODE, &isis_remote_lfa_max_metric_cmd);
|
||||
install_element(INTERFACE_NODE, &isis_ti_lfa_cmd);
|
||||
|
||||
install_element(ISIS_NODE, &log_adj_changes_cmd);
|
||||
|
596
isisd/isis_lfa.c
596
isisd/isis_lfa.c
@ -25,6 +25,8 @@
|
||||
#include "vrf.h"
|
||||
#include "table.h"
|
||||
#include "srcdest_table.h"
|
||||
#include "plist.h"
|
||||
#include "zclient.h"
|
||||
|
||||
#include "isis_common.h"
|
||||
#include "isisd.h"
|
||||
@ -37,11 +39,13 @@
|
||||
#include "isis_mt.h"
|
||||
#include "isis_tlvs.h"
|
||||
#include "isis_spf_private.h"
|
||||
#include "isisd/isis_errors.h"
|
||||
#include "isis_zebra.h"
|
||||
#include "isis_errors.h"
|
||||
|
||||
DEFINE_MTYPE_STATIC(ISISD, ISIS_SPF_NODE, "ISIS SPF Node");
|
||||
DEFINE_MTYPE_STATIC(ISISD, ISIS_LFA_TIEBREAKER, "ISIS LFA Tiebreaker");
|
||||
DEFINE_MTYPE_STATIC(ISISD, ISIS_LFA_EXCL_IFACE, "ISIS LFA Excluded Interface");
|
||||
DEFINE_MTYPE_STATIC(ISISD, ISIS_RLFA, "ISIS Remote LFA");
|
||||
|
||||
static inline int isis_spf_node_compare(const struct isis_spf_node *a,
|
||||
const struct isis_spf_node *b)
|
||||
@ -316,7 +320,7 @@ bool isis_lfa_excise_adj_check(const struct isis_spftree *spftree,
|
||||
{
|
||||
const struct lfa_protected_resource *resource;
|
||||
|
||||
if (spftree->type != SPF_TYPE_TI_LFA)
|
||||
if (spftree->type != SPF_TYPE_RLFA && spftree->type != SPF_TYPE_TI_LFA)
|
||||
return false;
|
||||
|
||||
/*
|
||||
@ -832,14 +836,14 @@ spf_vertex_check_is_affected(const struct isis_vertex *vertex,
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Check if a given TI-LFA post-convergence SPF vertex needs protection. */
|
||||
static bool tilfa_check_needs_protection(const struct isis_spftree *spftree_pc,
|
||||
const struct isis_vertex *vertex)
|
||||
/* Check if a given RLFA/TI-LFA post-convergence SPF vertex needs protection. */
|
||||
static bool lfa_check_needs_protection(const struct isis_spftree *spftree_pc,
|
||||
const struct isis_vertex *vertex)
|
||||
{
|
||||
struct isis_vertex *vertex_old;
|
||||
|
||||
/* Only local adjacencies need Adj-SID protection. */
|
||||
if (VTYPE_IS(vertex->type)
|
||||
/* Only local adjacencies need TI-LFA Adj-SID protection. */
|
||||
if (spftree_pc->type == SPF_TYPE_TI_LFA && VTYPE_IS(vertex->type)
|
||||
&& !isis_adj_find(spftree_pc->area, spftree_pc->level,
|
||||
vertex->N.id))
|
||||
return false;
|
||||
@ -849,6 +853,10 @@ static bool tilfa_check_needs_protection(const struct isis_spftree *spftree_pc,
|
||||
if (!vertex_old)
|
||||
return false;
|
||||
|
||||
/* Skip vertex if it's already protected by local LFA. */
|
||||
if (CHECK_FLAG(vertex_old->flags, F_ISIS_VERTEX_LFA_PROTECTED))
|
||||
return false;
|
||||
|
||||
return spf_vertex_check_is_affected(
|
||||
vertex_old, spftree_pc->sysid,
|
||||
&spftree_pc->lfa.protected_resource);
|
||||
@ -874,14 +882,12 @@ int isis_tilfa_check(struct isis_spftree *spftree_pc,
|
||||
if (!spftree_pc->area->srdb.enabled)
|
||||
return -1;
|
||||
|
||||
if (IS_DEBUG_LFA)
|
||||
vid2string(vertex, buf, sizeof(buf));
|
||||
|
||||
if (!tilfa_check_needs_protection(spftree_pc, vertex)) {
|
||||
if (!lfa_check_needs_protection(spftree_pc, vertex)) {
|
||||
if (IS_DEBUG_LFA)
|
||||
zlog_debug(
|
||||
"ISIS-LFA: %s %s unaffected by %s",
|
||||
vtype2string(vertex->type), buf,
|
||||
vtype2string(vertex->type),
|
||||
vid2string(vertex, buf, sizeof(buf)),
|
||||
lfa_protected_resource2str(
|
||||
&spftree_pc->lfa.protected_resource));
|
||||
|
||||
@ -902,7 +908,8 @@ int isis_tilfa_check(struct isis_spftree *spftree_pc,
|
||||
if (IS_DEBUG_LFA)
|
||||
zlog_debug(
|
||||
"ISIS-LFA: %s %s already covered by node protection",
|
||||
vtype2string(vertex->type), buf);
|
||||
vtype2string(vertex->type),
|
||||
vid2string(vertex, buf, sizeof(buf)));
|
||||
|
||||
return -1;
|
||||
}
|
||||
@ -915,7 +922,8 @@ int isis_tilfa_check(struct isis_spftree *spftree_pc,
|
||||
if (IS_DEBUG_LFA)
|
||||
zlog_debug(
|
||||
"ISIS-LFA: %s %s already covered by node protection",
|
||||
vtype2string(vertex->type), buf);
|
||||
vtype2string(vertex->type),
|
||||
vid2string(vertex, buf, sizeof(buf)));
|
||||
|
||||
return -1;
|
||||
}
|
||||
@ -924,7 +932,8 @@ int isis_tilfa_check(struct isis_spftree *spftree_pc,
|
||||
if (IS_DEBUG_LFA)
|
||||
zlog_debug(
|
||||
"ISIS-LFA: computing repair path(s) of %s %s w.r.t %s",
|
||||
vtype2string(vertex->type), buf,
|
||||
vtype2string(vertex->type),
|
||||
vid2string(vertex, buf, sizeof(buf)),
|
||||
lfa_protected_resource2str(
|
||||
&spftree_pc->lfa.protected_resource));
|
||||
|
||||
@ -939,7 +948,8 @@ int isis_tilfa_check(struct isis_spftree *spftree_pc,
|
||||
if (ret != 0)
|
||||
zlog_warn(
|
||||
"ISIS-LFA: failed to compute repair path(s) of %s %s w.r.t %s",
|
||||
vtype2string(vertex->type), buf,
|
||||
vtype2string(vertex->type),
|
||||
vid2string(vertex, buf, sizeof(buf)),
|
||||
lfa_protected_resource2str(
|
||||
&spftree_pc->lfa.protected_resource));
|
||||
|
||||
@ -978,13 +988,6 @@ static bool vertex_is_affected(struct isis_spftree *spftree_root,
|
||||
struct isis_vertex *vertex_child;
|
||||
struct isis_vertex_adj *vadj;
|
||||
bool reverse = false;
|
||||
char buf1[VID2STR_BUFFER];
|
||||
char buf2[VID2STR_BUFFER];
|
||||
|
||||
if (IS_DEBUG_LFA)
|
||||
zlog_debug("ISIS-LFA: vertex %s parent %s",
|
||||
vid2string(vertex, buf1, sizeof(buf1)),
|
||||
vid2string(pvertex, buf2, sizeof(buf2)));
|
||||
|
||||
if (p_space && resource->type == LFA_NODE_PROTECTION) {
|
||||
if (isis_spf_node_find(&resource->nodes, vertex->N.id))
|
||||
@ -1059,10 +1062,6 @@ static void lfa_calc_reach_nodes(struct isis_spftree *spftree,
|
||||
if (isis_spf_node_find(nodes, vertex->N.id))
|
||||
continue;
|
||||
|
||||
if (IS_DEBUG_LFA)
|
||||
zlog_debug("ISIS-LFA: checking %s",
|
||||
vid2string(vertex, buf, sizeof(buf)));
|
||||
|
||||
if (!vertex_is_affected(spftree_root, adj_nodes, p_space,
|
||||
vertex, resource)) {
|
||||
if (IS_DEBUG_LFA)
|
||||
@ -1166,7 +1165,7 @@ struct isis_spftree *isis_tilfa_compute(struct isis_area *area,
|
||||
struct isis_spf_node *adj_node;
|
||||
|
||||
if (IS_DEBUG_LFA)
|
||||
zlog_debug("ISIS-LFA: computing the P/Q spaces w.r.t. %s",
|
||||
zlog_debug("ISIS-LFA: computing TI-LFAs for %s",
|
||||
lfa_protected_resource2str(resource));
|
||||
|
||||
/* Populate list of nodes affected by link failure. */
|
||||
@ -1238,6 +1237,497 @@ int isis_spf_run_neighbors(struct isis_spftree *spftree)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Find Router ID of PQ node. */
|
||||
static struct in_addr *rlfa_pq_node_rtr_id(struct isis_spftree *spftree,
|
||||
const struct isis_vertex *vertex_pq)
|
||||
{
|
||||
struct isis_lsp *lsp;
|
||||
|
||||
lsp = isis_root_system_lsp(spftree->lspdb, vertex_pq->N.id);
|
||||
if (!lsp)
|
||||
return NULL;
|
||||
|
||||
if (lsp->tlvs->router_cap->router_id.s_addr == INADDR_ANY)
|
||||
return NULL;
|
||||
|
||||
return &lsp->tlvs->router_cap->router_id;
|
||||
}
|
||||
|
||||
/* Find PQ node by intersecting the P/Q spaces. This is a recursive function. */
|
||||
static const struct in_addr *
|
||||
rlfa_find_pq_node(struct isis_spftree *spftree_pc,
|
||||
struct isis_vertex *vertex_dest,
|
||||
const struct isis_vertex *vertex,
|
||||
const struct isis_vertex *vertex_child)
|
||||
{
|
||||
struct isis_area *area = spftree_pc->area;
|
||||
int level = spftree_pc->level;
|
||||
struct isis_vertex *pvertex;
|
||||
struct listnode *node;
|
||||
bool is_pnode, is_qnode;
|
||||
|
||||
if (!vertex_child)
|
||||
goto parents;
|
||||
if (vertex->type != VTYPE_NONPSEUDO_IS
|
||||
&& vertex->type != VTYPE_NONPSEUDO_TE_IS)
|
||||
goto parents;
|
||||
if (!VTYPE_IS(vertex_child->type))
|
||||
vertex_child = NULL;
|
||||
|
||||
/* Check if node is part of the extended P-space and/or Q-space. */
|
||||
is_pnode = lfa_ext_p_space_check(spftree_pc, vertex_dest, vertex);
|
||||
is_qnode = lfa_q_space_check(spftree_pc, vertex);
|
||||
|
||||
if (is_pnode && is_qnode) {
|
||||
const struct in_addr *rtr_id_pq;
|
||||
uint32_t max_metric;
|
||||
struct prefix_list *plist = NULL;
|
||||
|
||||
rtr_id_pq = rlfa_pq_node_rtr_id(spftree_pc, vertex);
|
||||
if (!rtr_id_pq) {
|
||||
if (IS_DEBUG_LFA) {
|
||||
char buf[VID2STR_BUFFER];
|
||||
|
||||
vid2string(vertex, buf, sizeof(buf));
|
||||
zlog_debug(
|
||||
"ISIS-LFA: tentative PQ node (%s %s) doesn't have a router-ID",
|
||||
vtype2string(vertex->type), buf);
|
||||
}
|
||||
goto parents;
|
||||
}
|
||||
|
||||
max_metric = spftree_pc->lfa.remote.max_metric;
|
||||
if (max_metric && vertex->d_N > max_metric) {
|
||||
if (IS_DEBUG_LFA)
|
||||
zlog_debug(
|
||||
"ISIS-LFA: skipping PQ node %pI4 (maximum metric)",
|
||||
rtr_id_pq);
|
||||
goto parents;
|
||||
}
|
||||
|
||||
plist = area->rlfa_plist[level - 1];
|
||||
if (plist) {
|
||||
struct prefix p;
|
||||
|
||||
p.family = AF_INET;
|
||||
p.prefixlen = IPV4_MAX_BITLEN;
|
||||
p.u.prefix4 = *rtr_id_pq;
|
||||
if (prefix_list_apply(plist, &p) == PREFIX_DENY) {
|
||||
if (IS_DEBUG_LFA)
|
||||
zlog_debug(
|
||||
"ISIS-LFA: PQ node %pI4 filtered by prefix-list",
|
||||
rtr_id_pq);
|
||||
goto parents;
|
||||
}
|
||||
}
|
||||
|
||||
if (IS_DEBUG_LFA)
|
||||
zlog_debug("ISIS-LFA: found PQ node: %pI4", rtr_id_pq);
|
||||
|
||||
return rtr_id_pq;
|
||||
}
|
||||
|
||||
parents:
|
||||
for (ALL_LIST_ELEMENTS_RO(vertex->parents, node, pvertex)) {
|
||||
const struct in_addr *rtr_id_pq;
|
||||
|
||||
rtr_id_pq = rlfa_find_pq_node(spftree_pc, vertex_dest, pvertex,
|
||||
vertex);
|
||||
if (rtr_id_pq)
|
||||
return rtr_id_pq;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int rlfa_cmp(const struct rlfa *a, const struct rlfa *b)
|
||||
{
|
||||
return prefix_cmp(&a->prefix, &b->prefix);
|
||||
}
|
||||
|
||||
static struct rlfa *rlfa_add(struct isis_spftree *spftree,
|
||||
struct isis_vertex *vertex,
|
||||
struct in_addr pq_address)
|
||||
{
|
||||
struct rlfa *rlfa;
|
||||
|
||||
assert(VTYPE_IP(vertex->type));
|
||||
rlfa = XCALLOC(MTYPE_ISIS_RLFA, sizeof(*rlfa));
|
||||
rlfa->prefix = vertex->N.ip.p.dest;
|
||||
rlfa->vertex = vertex;
|
||||
rlfa->pq_address = pq_address;
|
||||
rlfa_tree_add(&spftree->lfa.remote.rlfas, rlfa);
|
||||
|
||||
return rlfa;
|
||||
}
|
||||
|
||||
static void rlfa_delete(struct isis_spftree *spftree, struct rlfa *rlfa)
|
||||
{
|
||||
rlfa_tree_del(&spftree->lfa.remote.rlfas, rlfa);
|
||||
XFREE(MTYPE_ISIS_RLFA, rlfa);
|
||||
}
|
||||
|
||||
static struct rlfa *rlfa_lookup(struct isis_spftree *spftree,
|
||||
union prefixconstptr pu)
|
||||
{
|
||||
struct rlfa s = {};
|
||||
|
||||
s.prefix = *pu.p;
|
||||
return rlfa_tree_find(&spftree->lfa.remote.rlfas, &s);
|
||||
}
|
||||
|
||||
static int isis_area_verify_routes_cb(struct thread *thread)
|
||||
{
|
||||
struct isis_area *area = THREAD_ARG(thread);
|
||||
|
||||
if (IS_DEBUG_LFA)
|
||||
zlog_debug("ISIS-LFA: updating RLFAs in the RIB");
|
||||
|
||||
isis_area_verify_routes(area);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static mpls_label_t rlfa_nexthop_label(struct isis_spftree *spftree,
|
||||
struct isis_vertex_adj *vadj,
|
||||
struct zapi_rlfa_response *response)
|
||||
{
|
||||
struct isis_spf_adj *sadj = vadj->sadj;
|
||||
struct isis_adjacency *adj = sadj->adj;
|
||||
|
||||
/*
|
||||
* Special case to make unit tests work (use implicit-null labels
|
||||
* instead of artifical ones).
|
||||
*/
|
||||
if (CHECK_FLAG(spftree->flags, F_SPFTREE_NO_ADJACENCIES))
|
||||
return MPLS_LABEL_IMPLICIT_NULL;
|
||||
|
||||
for (unsigned int i = 0; i < response->nexthop_num; i++) {
|
||||
switch (response->nexthops[i].family) {
|
||||
case AF_INET:
|
||||
for (unsigned int j = 0; j < adj->ipv4_address_count;
|
||||
j++) {
|
||||
struct in_addr addr = adj->ipv4_addresses[j];
|
||||
|
||||
if (!IPV4_ADDR_SAME(
|
||||
&addr,
|
||||
&response->nexthops[i].gate.ipv4))
|
||||
continue;
|
||||
|
||||
return response->nexthops[i].label;
|
||||
}
|
||||
break;
|
||||
case AF_INET6:
|
||||
for (unsigned int j = 0; j < adj->ipv6_address_count;
|
||||
j++) {
|
||||
struct in6_addr addr = adj->ipv6_addresses[j];
|
||||
|
||||
if (!IPV6_ADDR_SAME(
|
||||
&addr,
|
||||
&response->nexthops[i].gate.ipv6))
|
||||
continue;
|
||||
|
||||
return response->nexthops[i].label;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return MPLS_INVALID_LABEL;
|
||||
}
|
||||
|
||||
int isis_rlfa_activate(struct isis_spftree *spftree, struct rlfa *rlfa,
|
||||
struct zapi_rlfa_response *response)
|
||||
{
|
||||
struct isis_area *area = spftree->area;
|
||||
struct isis_vertex *vertex = rlfa->vertex;
|
||||
struct isis_vertex_adj *vadj;
|
||||
struct listnode *node;
|
||||
|
||||
for (ALL_LIST_ELEMENTS_RO(vertex->Adj_N, node, vadj)) {
|
||||
mpls_label_t ldp_label;
|
||||
struct mpls_label_stack *label_stack;
|
||||
size_t num_labels = 0;
|
||||
size_t i = 0;
|
||||
|
||||
ldp_label = rlfa_nexthop_label(spftree, vadj, response);
|
||||
if (ldp_label == MPLS_INVALID_LABEL) {
|
||||
if (IS_DEBUG_LFA)
|
||||
zlog_debug(
|
||||
"ISIS-LFA: failed to activate RLFA: missing LDP label to reach PQ node through %s",
|
||||
sysid_print(vadj->sadj->id));
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (ldp_label != MPLS_LABEL_IMPLICIT_NULL)
|
||||
num_labels++;
|
||||
if (response->pq_label != MPLS_LABEL_IMPLICIT_NULL)
|
||||
num_labels++;
|
||||
if (vadj->sr.present
|
||||
&& vadj->sr.label != MPLS_LABEL_IMPLICIT_NULL)
|
||||
num_labels++;
|
||||
|
||||
/* Allocate label stack. */
|
||||
label_stack =
|
||||
XCALLOC(MTYPE_ISIS_NEXTHOP_LABELS,
|
||||
sizeof(struct mpls_label_stack)
|
||||
+ num_labels * sizeof(mpls_label_t));
|
||||
label_stack->num_labels = num_labels;
|
||||
|
||||
/* Push label allocated by the nexthop (outer label). */
|
||||
if (ldp_label != MPLS_LABEL_IMPLICIT_NULL)
|
||||
label_stack->label[i++] = ldp_label;
|
||||
/* Push label allocated by the PQ node (inner label). */
|
||||
if (response->pq_label != MPLS_LABEL_IMPLICIT_NULL)
|
||||
label_stack->label[i++] = response->pq_label;
|
||||
/* Preserve the original Prefix-SID label when it's present. */
|
||||
if (vadj->sr.present
|
||||
&& vadj->sr.label != MPLS_LABEL_IMPLICIT_NULL)
|
||||
label_stack->label[i++] = vadj->sr.label;
|
||||
|
||||
vadj->label_stack = label_stack;
|
||||
}
|
||||
|
||||
isis_route_create(&vertex->N.ip.p.dest, &vertex->N.ip.p.src,
|
||||
vertex->d_N, vertex->depth, &vertex->N.ip.sr,
|
||||
vertex->Adj_N, true, area,
|
||||
spftree->route_table_backup);
|
||||
spftree->lfa.protection_counters.rlfa[vertex->N.ip.priority] += 1;
|
||||
|
||||
thread_cancel(&area->t_rlfa_rib_update);
|
||||
thread_add_timer(master, isis_area_verify_routes_cb, area, 2,
|
||||
&area->t_rlfa_rib_update);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void isis_rlfa_deactivate(struct isis_spftree *spftree, struct rlfa *rlfa)
|
||||
{
|
||||
struct isis_area *area = spftree->area;
|
||||
struct isis_vertex *vertex = rlfa->vertex;
|
||||
struct route_node *rn;
|
||||
|
||||
rn = route_node_lookup(spftree->route_table_backup, &rlfa->prefix);
|
||||
if (!rn)
|
||||
return;
|
||||
isis_route_delete(area, rn, spftree->route_table_backup);
|
||||
spftree->lfa.protection_counters.rlfa[vertex->N.ip.priority] -= 1;
|
||||
|
||||
thread_cancel(&area->t_rlfa_rib_update);
|
||||
thread_add_timer(master, isis_area_verify_routes_cb, area, 2,
|
||||
&area->t_rlfa_rib_update);
|
||||
}
|
||||
|
||||
void isis_rlfa_list_init(struct isis_spftree *spftree)
|
||||
{
|
||||
rlfa_tree_init(&spftree->lfa.remote.rlfas);
|
||||
}
|
||||
|
||||
void isis_rlfa_list_clear(struct isis_spftree *spftree)
|
||||
{
|
||||
while (rlfa_tree_count(&spftree->lfa.remote.rlfas) > 0) {
|
||||
struct rlfa *rlfa;
|
||||
|
||||
rlfa = rlfa_tree_first(&spftree->lfa.remote.rlfas);
|
||||
isis_rlfa_deactivate(spftree, rlfa);
|
||||
rlfa_delete(spftree, rlfa);
|
||||
}
|
||||
}
|
||||
|
||||
void isis_rlfa_process_ldp_response(struct zapi_rlfa_response *response)
|
||||
{
|
||||
struct isis *isis;
|
||||
struct isis_area *area;
|
||||
struct isis_spftree *spftree;
|
||||
struct rlfa *rlfa;
|
||||
enum spf_tree_id tree_id;
|
||||
uint32_t spf_run_id;
|
||||
int level;
|
||||
|
||||
if (response->igp.protocol != ZEBRA_ROUTE_ISIS)
|
||||
return;
|
||||
|
||||
isis = isis_lookup_by_vrfid(response->igp.vrf_id);
|
||||
if (!isis)
|
||||
return;
|
||||
|
||||
area = isis_area_lookup(response->igp.isis.area_tag,
|
||||
response->igp.vrf_id);
|
||||
if (!area)
|
||||
return;
|
||||
|
||||
tree_id = response->igp.isis.spf.tree_id;
|
||||
if (tree_id != SPFTREE_IPV4 && tree_id != SPFTREE_IPV6) {
|
||||
zlog_warn("ISIS-LFA: invalid SPF tree ID received from LDP");
|
||||
return;
|
||||
}
|
||||
|
||||
level = response->igp.isis.spf.level;
|
||||
if (level != ISIS_LEVEL1 && level != ISIS_LEVEL2) {
|
||||
zlog_warn("ISIS-LFA: invalid IS-IS level received from LDP");
|
||||
return;
|
||||
}
|
||||
|
||||
spf_run_id = response->igp.isis.spf.run_id;
|
||||
spftree = area->spftree[tree_id][level - 1];
|
||||
if (spftree->runcount != spf_run_id)
|
||||
/* Outdated RLFA, ignore... */
|
||||
return;
|
||||
|
||||
rlfa = rlfa_lookup(spftree, &response->destination);
|
||||
if (!rlfa) {
|
||||
zlog_warn(
|
||||
"ISIS-LFA: couldn't find Remote-LFA %pFX received from LDP",
|
||||
&response->destination);
|
||||
return;
|
||||
}
|
||||
|
||||
if (response->pq_label != MPLS_INVALID_LABEL) {
|
||||
if (IS_DEBUG_LFA)
|
||||
zlog_debug(
|
||||
"ISIS-LFA: activating/updating RLFA for %pFX",
|
||||
&rlfa->prefix);
|
||||
|
||||
if (isis_rlfa_activate(spftree, rlfa, response) != 0)
|
||||
isis_rlfa_deactivate(spftree, rlfa);
|
||||
} else {
|
||||
if (IS_DEBUG_LFA)
|
||||
zlog_debug("ISIS-LFA: deactivating RLFA for %pFX",
|
||||
&rlfa->prefix);
|
||||
|
||||
isis_rlfa_deactivate(spftree, rlfa);
|
||||
}
|
||||
}
|
||||
|
||||
void isis_ldp_rlfa_handle_client_close(struct zapi_client_close_info *info)
|
||||
{
|
||||
struct isis *isis = isis_lookup_by_vrfid(VRF_DEFAULT);
|
||||
struct isis_area *area;
|
||||
struct listnode *node;
|
||||
|
||||
if (!isis)
|
||||
return;
|
||||
|
||||
/* Check if the LDP main client session closed */
|
||||
if (info->proto != ZEBRA_ROUTE_LDP || info->session_id == 0)
|
||||
return;
|
||||
|
||||
if (IS_DEBUG_LFA)
|
||||
zlog_debug("ISIS-LFA: LDP is down, deactivating all RLFAs");
|
||||
|
||||
for (ALL_LIST_ELEMENTS_RO(isis->area_list, node, area)) {
|
||||
for (int tree = SPFTREE_IPV4; tree < SPFTREE_COUNT; tree++) {
|
||||
for (int level = ISIS_LEVEL1; level <= ISIS_LEVELS;
|
||||
level++) {
|
||||
struct isis_spftree *spftree;
|
||||
|
||||
spftree = area->spftree[tree][level - 1];
|
||||
isis_rlfa_list_clear(spftree);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the given SPF vertex needs protection and, if so, attempt to
|
||||
* compute a Remote LFA for it.
|
||||
*
|
||||
* @param spftree_pc The post-convergence SPF tree
|
||||
* @param vertex IS-IS SPF vertex to check
|
||||
*/
|
||||
void isis_rlfa_check(struct isis_spftree *spftree_pc,
|
||||
struct isis_vertex *vertex)
|
||||
{
|
||||
struct isis_spftree *spftree_old = spftree_pc->lfa.old.spftree;
|
||||
struct rlfa *rlfa;
|
||||
const struct in_addr *rtr_id_pq;
|
||||
char buf[VID2STR_BUFFER];
|
||||
|
||||
if (!lfa_check_needs_protection(spftree_pc, vertex)) {
|
||||
if (IS_DEBUG_LFA)
|
||||
zlog_debug(
|
||||
"ISIS-LFA: %s %s unaffected by %s",
|
||||
vtype2string(vertex->type),
|
||||
vid2string(vertex, buf, sizeof(buf)),
|
||||
lfa_protected_resource2str(
|
||||
&spftree_pc->lfa.protected_resource));
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (IS_DEBUG_LFA)
|
||||
zlog_debug(
|
||||
"ISIS-LFA: computing repair path(s) of %s %s w.r.t %s",
|
||||
vtype2string(vertex->type),
|
||||
vid2string(vertex, buf, sizeof(buf)),
|
||||
lfa_protected_resource2str(
|
||||
&spftree_pc->lfa.protected_resource));
|
||||
|
||||
/* Find PQ node. */
|
||||
rtr_id_pq = rlfa_find_pq_node(spftree_pc, vertex, vertex, NULL);
|
||||
if (!rtr_id_pq) {
|
||||
if (IS_DEBUG_LFA)
|
||||
zlog_debug("ISIS-LFA: no acceptable PQ node found");
|
||||
return;
|
||||
}
|
||||
|
||||
/* Store valid RLFA and store LDP label for the PQ node. */
|
||||
rlfa = rlfa_add(spftree_old, vertex, *rtr_id_pq);
|
||||
|
||||
/* Register RLFA with LDP. */
|
||||
if (isis_zebra_rlfa_register(spftree_old, rlfa) != 0)
|
||||
rlfa_delete(spftree_old, rlfa);
|
||||
}
|
||||
|
||||
/**
|
||||
* Compute the Remote LFA backup paths for a given protected interface.
|
||||
*
|
||||
* @param area IS-IS area
|
||||
* @param spftree IS-IS SPF tree
|
||||
* @param spftree_reverse IS-IS Reverse SPF tree
|
||||
* @param max_metric Remote LFA maximum metric
|
||||
* @param resource Protected resource
|
||||
*
|
||||
* @return Pointer to the post-convergence SPF tree
|
||||
*/
|
||||
struct isis_spftree *isis_rlfa_compute(struct isis_area *area,
|
||||
struct isis_spftree *spftree,
|
||||
struct isis_spftree *spftree_reverse,
|
||||
uint32_t max_metric,
|
||||
struct lfa_protected_resource *resource)
|
||||
{
|
||||
struct isis_spftree *spftree_pc;
|
||||
|
||||
if (IS_DEBUG_LFA)
|
||||
zlog_debug("ISIS-LFA: computing remote LFAs for %s",
|
||||
lfa_protected_resource2str(resource));
|
||||
|
||||
/* Create post-convergence SPF tree. */
|
||||
spftree_pc = isis_spftree_new(area, spftree->lspdb, spftree->sysid,
|
||||
spftree->level, spftree->tree_id,
|
||||
SPF_TYPE_RLFA, spftree->flags);
|
||||
spftree_pc->lfa.old.spftree = spftree;
|
||||
spftree_pc->lfa.old.spftree_reverse = spftree_reverse;
|
||||
spftree_pc->lfa.remote.max_metric = max_metric;
|
||||
spftree_pc->lfa.protected_resource = *resource;
|
||||
|
||||
/* Compute the extended P-space and Q-space. */
|
||||
lfa_calc_pq_spaces(spftree_pc, resource);
|
||||
|
||||
if (IS_DEBUG_LFA)
|
||||
zlog_debug(
|
||||
"ISIS-LFA: computing the post convergence SPT w.r.t. %s",
|
||||
lfa_protected_resource2str(resource));
|
||||
|
||||
/* Re-run SPF in the local node to find the post-convergence paths. */
|
||||
isis_run_spf(spftree_pc);
|
||||
|
||||
return spftree_pc;
|
||||
}
|
||||
|
||||
/* Calculate the distance from the root node to the given IP destination. */
|
||||
static int lfa_calc_dist_destination(struct isis_spftree *spftree,
|
||||
const struct isis_vertex *vertex_N,
|
||||
@ -1451,8 +1941,7 @@ static bool clfa_node_protecting_check(struct isis_spftree *spftree,
|
||||
}
|
||||
|
||||
static struct list *
|
||||
isis_lfa_tiebreakers(struct isis_area *area, struct isis_circuit *circuit,
|
||||
struct isis_spftree *spftree,
|
||||
isis_lfa_tiebreakers(struct isis_area *area, struct isis_spftree *spftree,
|
||||
struct lfa_protected_resource *resource,
|
||||
struct isis_vertex *vertex,
|
||||
struct isis_spf_adj *sadj_primary, struct list *lfa_list)
|
||||
@ -1572,6 +2061,10 @@ void isis_lfa_compute(struct isis_area *area, struct isis_circuit *circuit,
|
||||
|
||||
resource->type = LFA_LINK_PROTECTION;
|
||||
|
||||
if (IS_DEBUG_LFA)
|
||||
zlog_debug("ISIS-LFA: computing local LFAs for %s",
|
||||
lfa_protected_resource2str(resource));
|
||||
|
||||
for (ALL_QUEUE_ELEMENTS_RO(&spftree->paths, vnode, vertex)) {
|
||||
struct list *lfa_list;
|
||||
struct list *filtered_lfa_list;
|
||||
@ -1591,7 +2084,8 @@ void isis_lfa_compute(struct isis_area *area, struct isis_circuit *circuit,
|
||||
resource)) {
|
||||
if (IS_DEBUG_LFA)
|
||||
zlog_debug(
|
||||
"ISIS-LFA: route unaffected by %s",
|
||||
"ISIS-LFA: %s %s unaffected by %s",
|
||||
vtype2string(vertex->type), buf,
|
||||
lfa_protected_resource2str(resource));
|
||||
continue;
|
||||
}
|
||||
@ -1697,15 +2191,18 @@ void isis_lfa_compute(struct isis_area *area, struct isis_circuit *circuit,
|
||||
|
||||
if (list_isempty(lfa_list)) {
|
||||
if (IS_DEBUG_LFA)
|
||||
zlog_debug("ISIS-LFA: no valid LFAs found");
|
||||
zlog_debug(
|
||||
"ISIS-LFA: no valid local LFAs found");
|
||||
list_delete(&lfa_list);
|
||||
continue;
|
||||
}
|
||||
|
||||
SET_FLAG(vertex->flags, F_ISIS_VERTEX_LFA_PROTECTED);
|
||||
|
||||
/* Check tie-breakers. */
|
||||
filtered_lfa_list =
|
||||
isis_lfa_tiebreakers(area, circuit, spftree, resource,
|
||||
vertex, sadj_primary, lfa_list);
|
||||
isis_lfa_tiebreakers(area, spftree, resource, vertex,
|
||||
sadj_primary, lfa_list);
|
||||
|
||||
/* Create backup route using the best LFAs. */
|
||||
allow_ecmp = area->lfa_load_sharing[level - 1];
|
||||
@ -1746,7 +2243,7 @@ static void isis_spf_run_tilfa(struct isis_area *area,
|
||||
}
|
||||
|
||||
/**
|
||||
* Run the LFA/TI-LFA algorithms for all protected interfaces.
|
||||
* Run the LFA/RLFA/TI-LFA algorithms for all protected interfaces.
|
||||
*
|
||||
* @param area IS-IS area
|
||||
* @param spftree IS-IS SPF tree
|
||||
@ -1756,13 +2253,11 @@ void isis_spf_run_lfa(struct isis_area *area, struct isis_spftree *spftree)
|
||||
struct isis_spftree *spftree_reverse = NULL;
|
||||
struct isis_circuit *circuit;
|
||||
struct listnode *node;
|
||||
bool tilfa_configured;
|
||||
int level = spftree->level;
|
||||
|
||||
tilfa_configured = (area->tilfa_protected_links[level - 1] > 0);
|
||||
|
||||
/* Run reverse SPF locally. */
|
||||
if (tilfa_configured)
|
||||
if (area->rlfa_protected_links[level - 1] > 0
|
||||
|| area->tilfa_protected_links[level - 1] > 0)
|
||||
spftree_reverse = isis_spf_reverse_run(spftree);
|
||||
|
||||
/* Run forward SPF on all adjacent routers. */
|
||||
@ -1808,15 +2303,32 @@ void isis_spf_run_lfa(struct isis_area *area, struct isis_spftree *spftree)
|
||||
continue;
|
||||
}
|
||||
|
||||
if (circuit->lfa_protection[level - 1])
|
||||
if (circuit->lfa_protection[level - 1]) {
|
||||
/* Run local LFA. */
|
||||
isis_lfa_compute(area, circuit, spftree, &resource);
|
||||
else if (circuit->tilfa_protection[level - 1]) {
|
||||
|
||||
if (circuit->rlfa_protection[level - 1]) {
|
||||
struct isis_spftree *spftree_pc;
|
||||
uint32_t max_metric;
|
||||
|
||||
/* Run remote LFA. */
|
||||
assert(spftree_reverse);
|
||||
max_metric =
|
||||
circuit->rlfa_max_metric[level - 1];
|
||||
spftree_pc = isis_rlfa_compute(
|
||||
area, spftree, spftree_reverse,
|
||||
max_metric, &resource);
|
||||
listnode_add(spftree->lfa.remote.pc_spftrees,
|
||||
spftree_pc);
|
||||
}
|
||||
} else if (circuit->tilfa_protection[level - 1]) {
|
||||
/* Run TI-LFA. */
|
||||
assert(spftree_reverse);
|
||||
isis_spf_run_tilfa(area, circuit, spftree,
|
||||
spftree_reverse, &resource);
|
||||
}
|
||||
}
|
||||
|
||||
if (tilfa_configured)
|
||||
if (spftree_reverse)
|
||||
isis_spftree_del(spftree_reverse);
|
||||
}
|
||||
|
@ -21,8 +21,10 @@
|
||||
#define _FRR_ISIS_LFA_H
|
||||
|
||||
#include "lib/typesafe.h"
|
||||
#include "lib/zclient.h"
|
||||
|
||||
PREDECL_RBTREE_UNIQ(lfa_tiebreaker_tree)
|
||||
PREDECL_RBTREE_UNIQ(rlfa_tree)
|
||||
|
||||
enum lfa_tiebreaker_type {
|
||||
LFA_TIEBREAKER_DOWNSTREAM = 0,
|
||||
@ -41,6 +43,15 @@ int lfa_tiebreaker_cmp(const struct lfa_tiebreaker *a,
|
||||
DECLARE_RBTREE_UNIQ(lfa_tiebreaker_tree, struct lfa_tiebreaker, entry,
|
||||
lfa_tiebreaker_cmp)
|
||||
|
||||
struct rlfa {
|
||||
struct rlfa_tree_item entry;
|
||||
struct prefix prefix;
|
||||
struct isis_vertex *vertex;
|
||||
struct in_addr pq_address;
|
||||
};
|
||||
int rlfa_cmp(const struct rlfa *a, const struct rlfa *b);
|
||||
DECLARE_RBTREE_UNIQ(rlfa_tree, struct rlfa, entry, rlfa_cmp)
|
||||
|
||||
enum isis_tilfa_sid_type {
|
||||
TILFA_SID_PREFIX = 1,
|
||||
TILFA_SID_ADJ,
|
||||
@ -145,6 +156,19 @@ bool isis_lfa_excise_node_check(const struct isis_spftree *spftree,
|
||||
const uint8_t *id);
|
||||
struct isis_spftree *isis_spf_reverse_run(const struct isis_spftree *spftree);
|
||||
int isis_spf_run_neighbors(struct isis_spftree *spftree);
|
||||
int isis_rlfa_activate(struct isis_spftree *spftree, struct rlfa *rlfa,
|
||||
struct zapi_rlfa_response *response);
|
||||
void isis_rlfa_deactivate(struct isis_spftree *spftree, struct rlfa *rlfa);
|
||||
void isis_rlfa_list_init(struct isis_spftree *spftree);
|
||||
void isis_rlfa_list_clear(struct isis_spftree *spftree);
|
||||
void isis_rlfa_process_ldp_response(struct zapi_rlfa_response *response);
|
||||
void isis_ldp_rlfa_handle_client_close(struct zapi_client_close_info *info);
|
||||
void isis_rlfa_check(struct isis_spftree *spftree, struct isis_vertex *vertex);
|
||||
struct isis_spftree *isis_rlfa_compute(struct isis_area *area,
|
||||
struct isis_spftree *spftree,
|
||||
struct isis_spftree *spftree_reverse,
|
||||
uint32_t max_metric,
|
||||
struct lfa_protected_resource *resource);
|
||||
void isis_lfa_compute(struct isis_area *area, struct isis_circuit *circuit,
|
||||
struct isis_spftree *spftree,
|
||||
struct lfa_protected_resource *resource);
|
||||
|
@ -246,6 +246,8 @@ int main(int argc, char **argv, char **envp)
|
||||
access_list_delete_hook(isis_filter_update);
|
||||
isis_vrf_init();
|
||||
prefix_list_init();
|
||||
prefix_list_add_hook(isis_prefix_list_update);
|
||||
prefix_list_delete_hook(isis_prefix_list_update);
|
||||
isis_init();
|
||||
isis_circuit_init();
|
||||
#ifdef FABRICD
|
||||
|
@ -46,3 +46,4 @@ DEFINE_MTYPE(ISISD, ISIS_EXT_ROUTE, "ISIS redistributed route")
|
||||
DEFINE_MTYPE(ISISD, ISIS_EXT_INFO, "ISIS redistributed route info")
|
||||
DEFINE_MTYPE(ISISD, ISIS_MPLS_TE, "ISIS MPLS_TE parameters")
|
||||
DEFINE_MTYPE(ISISD, ISIS_ACL_NAME, "ISIS access-list name")
|
||||
DEFINE_MTYPE(ISISD, ISIS_PLIST_NAME, "ISIS prefix-list name")
|
||||
|
@ -45,5 +45,6 @@ DECLARE_MTYPE(ISIS_EXT_ROUTE)
|
||||
DECLARE_MTYPE(ISIS_EXT_INFO)
|
||||
DECLARE_MTYPE(ISIS_MPLS_TE)
|
||||
DECLARE_MTYPE(ISIS_ACL_NAME)
|
||||
DECLARE_MTYPE(ISIS_PLIST_NAME)
|
||||
|
||||
#endif /* _QUAGGA_ISIS_MEMORY_H */
|
||||
|
@ -484,6 +484,14 @@ const struct frr_yang_module_info frr_isisd_info = {
|
||||
.modify = isis_instance_fast_reroute_level_1_lfa_tiebreaker_type_modify,
|
||||
}
|
||||
},
|
||||
{
|
||||
.xpath = "/frr-isisd:isis/instance/fast-reroute/level-1/remote-lfa/prefix-list",
|
||||
.cbs = {
|
||||
.cli_show = cli_show_isis_frr_remote_lfa_plist,
|
||||
.modify = isis_instance_fast_reroute_level_1_remote_lfa_prefix_list_modify,
|
||||
.destroy = isis_instance_fast_reroute_level_1_remote_lfa_prefix_list_destroy,
|
||||
}
|
||||
},
|
||||
{
|
||||
.xpath = "/frr-isisd:isis/instance/fast-reroute/level-2/lfa/load-sharing",
|
||||
.cbs = {
|
||||
@ -513,6 +521,14 @@ const struct frr_yang_module_info frr_isisd_info = {
|
||||
.modify = isis_instance_fast_reroute_level_2_lfa_tiebreaker_type_modify,
|
||||
}
|
||||
},
|
||||
{
|
||||
.xpath = "/frr-isisd:isis/instance/fast-reroute/level-2/remote-lfa/prefix-list",
|
||||
.cbs = {
|
||||
.cli_show = cli_show_isis_frr_remote_lfa_plist,
|
||||
.modify = isis_instance_fast_reroute_level_2_remote_lfa_prefix_list_modify,
|
||||
.destroy = isis_instance_fast_reroute_level_2_remote_lfa_prefix_list_destroy,
|
||||
}
|
||||
},
|
||||
{
|
||||
.xpath = "/frr-isisd:isis/instance/log-adjacency-changes",
|
||||
.cbs = {
|
||||
@ -926,6 +942,20 @@ const struct frr_yang_module_info frr_isisd_info = {
|
||||
.destroy = lib_interface_isis_fast_reroute_level_1_lfa_exclude_interface_destroy,
|
||||
}
|
||||
},
|
||||
{
|
||||
.xpath = "/frr-interface:lib/interface/frr-isisd:isis/fast-reroute/level-1/remote-lfa/enable",
|
||||
.cbs = {
|
||||
.modify = lib_interface_isis_fast_reroute_level_1_remote_lfa_enable_modify,
|
||||
}
|
||||
},
|
||||
{
|
||||
.xpath = "/frr-interface:lib/interface/frr-isisd:isis/fast-reroute/level-1/remote-lfa/maximum-metric",
|
||||
.cbs = {
|
||||
.cli_show = cli_show_frr_remote_lfa_max_metric,
|
||||
.modify = lib_interface_isis_fast_reroute_level_1_remote_lfa_maximum_metric_modify,
|
||||
.destroy = lib_interface_isis_fast_reroute_level_1_remote_lfa_maximum_metric_destroy,
|
||||
}
|
||||
},
|
||||
{
|
||||
.xpath = "/frr-interface:lib/interface/frr-isisd:isis/fast-reroute/level-1/ti-lfa/enable",
|
||||
.cbs = {
|
||||
@ -952,6 +982,20 @@ const struct frr_yang_module_info frr_isisd_info = {
|
||||
.destroy = lib_interface_isis_fast_reroute_level_2_lfa_exclude_interface_destroy,
|
||||
}
|
||||
},
|
||||
{
|
||||
.xpath = "/frr-interface:lib/interface/frr-isisd:isis/fast-reroute/level-2/remote-lfa/enable",
|
||||
.cbs = {
|
||||
.modify = lib_interface_isis_fast_reroute_level_2_remote_lfa_enable_modify,
|
||||
}
|
||||
},
|
||||
{
|
||||
.xpath = "/frr-interface:lib/interface/frr-isisd:isis/fast-reroute/level-2/remote-lfa/maximum-metric",
|
||||
.cbs = {
|
||||
.cli_show = cli_show_frr_remote_lfa_max_metric,
|
||||
.modify = lib_interface_isis_fast_reroute_level_2_remote_lfa_maximum_metric_modify,
|
||||
.destroy = lib_interface_isis_fast_reroute_level_2_remote_lfa_maximum_metric_destroy,
|
||||
}
|
||||
},
|
||||
{
|
||||
.xpath = "/frr-interface:lib/interface/frr-isisd:isis/fast-reroute/level-2/ti-lfa/enable",
|
||||
.cbs = {
|
||||
|
@ -183,6 +183,10 @@ int isis_instance_fast_reroute_level_1_lfa_tiebreaker_destroy(
|
||||
struct nb_cb_destroy_args *args);
|
||||
int isis_instance_fast_reroute_level_1_lfa_tiebreaker_type_modify(
|
||||
struct nb_cb_modify_args *args);
|
||||
int isis_instance_fast_reroute_level_1_remote_lfa_prefix_list_modify(
|
||||
struct nb_cb_modify_args *args);
|
||||
int isis_instance_fast_reroute_level_1_remote_lfa_prefix_list_destroy(
|
||||
struct nb_cb_destroy_args *args);
|
||||
int isis_instance_fast_reroute_level_2_lfa_load_sharing_modify(
|
||||
struct nb_cb_modify_args *args);
|
||||
int isis_instance_fast_reroute_level_2_lfa_priority_limit_modify(
|
||||
@ -195,6 +199,10 @@ int isis_instance_fast_reroute_level_2_lfa_tiebreaker_destroy(
|
||||
struct nb_cb_destroy_args *args);
|
||||
int isis_instance_fast_reroute_level_2_lfa_tiebreaker_type_modify(
|
||||
struct nb_cb_modify_args *args);
|
||||
int isis_instance_fast_reroute_level_2_remote_lfa_prefix_list_modify(
|
||||
struct nb_cb_modify_args *args);
|
||||
int isis_instance_fast_reroute_level_2_remote_lfa_prefix_list_destroy(
|
||||
struct nb_cb_destroy_args *args);
|
||||
int isis_instance_log_adjacency_changes_modify(struct nb_cb_modify_args *args);
|
||||
int isis_instance_mpls_te_create(struct nb_cb_create_args *args);
|
||||
int isis_instance_mpls_te_destroy(struct nb_cb_destroy_args *args);
|
||||
@ -300,6 +308,12 @@ int lib_interface_isis_fast_reroute_level_1_lfa_exclude_interface_create(
|
||||
struct nb_cb_create_args *args);
|
||||
int lib_interface_isis_fast_reroute_level_1_lfa_exclude_interface_destroy(
|
||||
struct nb_cb_destroy_args *args);
|
||||
int lib_interface_isis_fast_reroute_level_1_remote_lfa_enable_modify(
|
||||
struct nb_cb_modify_args *args);
|
||||
int lib_interface_isis_fast_reroute_level_1_remote_lfa_maximum_metric_modify(
|
||||
struct nb_cb_modify_args *args);
|
||||
int lib_interface_isis_fast_reroute_level_1_remote_lfa_maximum_metric_destroy(
|
||||
struct nb_cb_destroy_args *args);
|
||||
int lib_interface_isis_fast_reroute_level_1_ti_lfa_enable_modify(
|
||||
struct nb_cb_modify_args *args);
|
||||
int lib_interface_isis_fast_reroute_level_1_ti_lfa_node_protection_modify(
|
||||
@ -310,6 +324,12 @@ int lib_interface_isis_fast_reroute_level_2_lfa_exclude_interface_create(
|
||||
struct nb_cb_create_args *args);
|
||||
int lib_interface_isis_fast_reroute_level_2_lfa_exclude_interface_destroy(
|
||||
struct nb_cb_destroy_args *args);
|
||||
int lib_interface_isis_fast_reroute_level_2_remote_lfa_enable_modify(
|
||||
struct nb_cb_modify_args *args);
|
||||
int lib_interface_isis_fast_reroute_level_2_remote_lfa_maximum_metric_modify(
|
||||
struct nb_cb_modify_args *args);
|
||||
int lib_interface_isis_fast_reroute_level_2_remote_lfa_maximum_metric_destroy(
|
||||
struct nb_cb_destroy_args *args);
|
||||
int lib_interface_isis_fast_reroute_level_2_ti_lfa_enable_modify(
|
||||
struct nb_cb_modify_args *args);
|
||||
int lib_interface_isis_fast_reroute_level_2_ti_lfa_node_protection_modify(
|
||||
@ -467,6 +487,8 @@ void cli_show_isis_frr_lfa_tiebreaker(struct vty *vty, struct lyd_node *dnode,
|
||||
bool show_defaults);
|
||||
void cli_show_isis_frr_lfa_load_sharing(struct vty *vty, struct lyd_node *dnode,
|
||||
bool show_defaults);
|
||||
void cli_show_isis_frr_remote_lfa_plist(struct vty *vty, struct lyd_node *dnode,
|
||||
bool show_defaults);
|
||||
void cli_show_ip_isis_passive(struct vty *vty, struct lyd_node *dnode,
|
||||
bool show_defaults);
|
||||
void cli_show_ip_isis_password(struct vty *vty, struct lyd_node *dnode,
|
||||
@ -503,6 +525,8 @@ void cli_show_ip_isis_frr(struct vty *vty, struct lyd_node *dnode,
|
||||
bool show_defaults);
|
||||
void cli_show_frr_lfa_exclude_interface(struct vty *vty, struct lyd_node *dnode,
|
||||
bool show_defaults);
|
||||
void cli_show_frr_remote_lfa_max_metric(struct vty *vty, struct lyd_node *dnode,
|
||||
bool show_defaults);
|
||||
void cli_show_ip_isis_circ_type(struct vty *vty, struct lyd_node *dnode,
|
||||
bool show_defaults);
|
||||
void cli_show_ip_isis_network_type(struct vty *vty, struct lyd_node *dnode,
|
||||
|
@ -28,6 +28,7 @@
|
||||
#include "log.h"
|
||||
#include "bfd.h"
|
||||
#include "filter.h"
|
||||
#include "plist.h"
|
||||
#include "spf_backoff.h"
|
||||
#include "lib_errors.h"
|
||||
#include "vrf.h"
|
||||
@ -1551,6 +1552,45 @@ int isis_instance_fast_reroute_level_1_lfa_tiebreaker_type_modify(
|
||||
return NB_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
* XPath: /frr-isisd:isis/instance/fast-reroute/level-1/remote-lfa/prefix-list
|
||||
*/
|
||||
int isis_instance_fast_reroute_level_1_remote_lfa_prefix_list_modify(
|
||||
struct nb_cb_modify_args *args)
|
||||
{
|
||||
struct isis_area *area;
|
||||
const char *plist_name;
|
||||
|
||||
if (args->event != NB_EV_APPLY)
|
||||
return NB_OK;
|
||||
|
||||
area = nb_running_get_entry(args->dnode, NULL, true);
|
||||
plist_name = yang_dnode_get_string(args->dnode, NULL);
|
||||
|
||||
area->rlfa_plist_name[0] = XSTRDUP(MTYPE_ISIS_PLIST_NAME, plist_name);
|
||||
area->rlfa_plist[0] = prefix_list_lookup(AFI_IP, plist_name);
|
||||
lsp_regenerate_schedule(area, area->is_type, 0);
|
||||
|
||||
return NB_OK;
|
||||
}
|
||||
|
||||
int isis_instance_fast_reroute_level_1_remote_lfa_prefix_list_destroy(
|
||||
struct nb_cb_destroy_args *args)
|
||||
{
|
||||
struct isis_area *area;
|
||||
|
||||
if (args->event != NB_EV_APPLY)
|
||||
return NB_OK;
|
||||
|
||||
area = nb_running_get_entry(args->dnode, NULL, true);
|
||||
|
||||
XFREE(MTYPE_ISIS_PLIST_NAME, area->rlfa_plist_name[0]);
|
||||
area->rlfa_plist[0] = NULL;
|
||||
lsp_regenerate_schedule(area, area->is_type, 0);
|
||||
|
||||
return NB_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
* XPath: /frr-isisd:isis/instance/fast-reroute/level-2/lfa/load-sharing
|
||||
*/
|
||||
@ -1661,6 +1701,45 @@ int isis_instance_fast_reroute_level_2_lfa_tiebreaker_type_modify(
|
||||
return NB_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
* XPath: /frr-isisd:isis/instance/fast-reroute/level-2/remote-lfa/prefix-list
|
||||
*/
|
||||
int isis_instance_fast_reroute_level_2_remote_lfa_prefix_list_modify(
|
||||
struct nb_cb_modify_args *args)
|
||||
{
|
||||
struct isis_area *area;
|
||||
const char *plist_name;
|
||||
|
||||
if (args->event != NB_EV_APPLY)
|
||||
return NB_OK;
|
||||
|
||||
area = nb_running_get_entry(args->dnode, NULL, true);
|
||||
plist_name = yang_dnode_get_string(args->dnode, NULL);
|
||||
|
||||
area->rlfa_plist_name[1] = XSTRDUP(MTYPE_ISIS_PLIST_NAME, plist_name);
|
||||
area->rlfa_plist[1] = prefix_list_lookup(AFI_IP, plist_name);
|
||||
lsp_regenerate_schedule(area, area->is_type, 0);
|
||||
|
||||
return NB_OK;
|
||||
}
|
||||
|
||||
int isis_instance_fast_reroute_level_2_remote_lfa_prefix_list_destroy(
|
||||
struct nb_cb_destroy_args *args)
|
||||
{
|
||||
struct isis_area *area;
|
||||
|
||||
if (args->event != NB_EV_APPLY)
|
||||
return NB_OK;
|
||||
|
||||
area = nb_running_get_entry(args->dnode, NULL, true);
|
||||
|
||||
XFREE(MTYPE_ISIS_PLIST_NAME, area->rlfa_plist_name[1]);
|
||||
area->rlfa_plist[1] = NULL;
|
||||
lsp_regenerate_schedule(area, area->is_type, 0);
|
||||
|
||||
return NB_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
* XPath: /frr-isisd:isis/instance/log-adjacency-changes
|
||||
*/
|
||||
@ -3446,6 +3525,74 @@ int lib_interface_isis_fast_reroute_level_1_lfa_exclude_interface_destroy(
|
||||
return NB_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
* XPath:
|
||||
* /frr-interface:lib/interface/frr-isisd:isis/fast-reroute/level-1/remote-lfa/enable
|
||||
*/
|
||||
int lib_interface_isis_fast_reroute_level_1_remote_lfa_enable_modify(
|
||||
struct nb_cb_modify_args *args)
|
||||
{
|
||||
struct isis_area *area;
|
||||
struct isis_circuit *circuit;
|
||||
|
||||
if (args->event != NB_EV_APPLY)
|
||||
return NB_OK;
|
||||
|
||||
circuit = nb_running_get_entry(args->dnode, NULL, true);
|
||||
circuit->rlfa_protection[0] = yang_dnode_get_bool(args->dnode, NULL);
|
||||
if (circuit->rlfa_protection[0])
|
||||
circuit->area->rlfa_protected_links[0]++;
|
||||
else {
|
||||
assert(circuit->area->rlfa_protected_links[0] > 0);
|
||||
circuit->area->rlfa_protected_links[0]--;
|
||||
}
|
||||
|
||||
area = circuit->area;
|
||||
lsp_regenerate_schedule(area, area->is_type, 0);
|
||||
|
||||
return NB_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
* XPath:
|
||||
* /frr-interface:lib/interface/frr-isisd:isis/fast-reroute/level-1/remote-lfa/maximum-metric
|
||||
*/
|
||||
int lib_interface_isis_fast_reroute_level_1_remote_lfa_maximum_metric_modify(
|
||||
struct nb_cb_modify_args *args)
|
||||
{
|
||||
struct isis_area *area;
|
||||
struct isis_circuit *circuit;
|
||||
|
||||
if (args->event != NB_EV_APPLY)
|
||||
return NB_OK;
|
||||
|
||||
circuit = nb_running_get_entry(args->dnode, NULL, true);
|
||||
circuit->rlfa_max_metric[0] = yang_dnode_get_uint32(args->dnode, NULL);
|
||||
|
||||
area = circuit->area;
|
||||
lsp_regenerate_schedule(area, area->is_type, 0);
|
||||
|
||||
return NB_OK;
|
||||
}
|
||||
|
||||
int lib_interface_isis_fast_reroute_level_1_remote_lfa_maximum_metric_destroy(
|
||||
struct nb_cb_destroy_args *args)
|
||||
{
|
||||
struct isis_area *area;
|
||||
struct isis_circuit *circuit;
|
||||
|
||||
if (args->event != NB_EV_APPLY)
|
||||
return NB_OK;
|
||||
|
||||
circuit = nb_running_get_entry(args->dnode, NULL, true);
|
||||
circuit->rlfa_max_metric[0] = 0;
|
||||
|
||||
area = circuit->area;
|
||||
lsp_regenerate_schedule(area, area->is_type, 0);
|
||||
|
||||
return NB_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
* XPath:
|
||||
* /frr-interface:lib/interface/frr-isisd:isis/fast-reroute/level-1/ti-lfa/enable
|
||||
@ -3569,6 +3716,74 @@ int lib_interface_isis_fast_reroute_level_2_lfa_exclude_interface_destroy(
|
||||
return NB_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
* XPath:
|
||||
* /frr-interface:lib/interface/frr-isisd:isis/fast-reroute/level-2/remote-lfa/enable
|
||||
*/
|
||||
int lib_interface_isis_fast_reroute_level_2_remote_lfa_enable_modify(
|
||||
struct nb_cb_modify_args *args)
|
||||
{
|
||||
struct isis_area *area;
|
||||
struct isis_circuit *circuit;
|
||||
|
||||
if (args->event != NB_EV_APPLY)
|
||||
return NB_OK;
|
||||
|
||||
circuit = nb_running_get_entry(args->dnode, NULL, true);
|
||||
circuit->rlfa_protection[1] = yang_dnode_get_bool(args->dnode, NULL);
|
||||
if (circuit->rlfa_protection[1])
|
||||
circuit->area->rlfa_protected_links[1]++;
|
||||
else {
|
||||
assert(circuit->area->rlfa_protected_links[1] > 0);
|
||||
circuit->area->rlfa_protected_links[1]--;
|
||||
}
|
||||
|
||||
area = circuit->area;
|
||||
lsp_regenerate_schedule(area, area->is_type, 0);
|
||||
|
||||
return NB_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
* XPath:
|
||||
* /frr-interface:lib/interface/frr-isisd:isis/fast-reroute/level-2/remote-lfa/maximum-metric
|
||||
*/
|
||||
int lib_interface_isis_fast_reroute_level_2_remote_lfa_maximum_metric_modify(
|
||||
struct nb_cb_modify_args *args)
|
||||
{
|
||||
struct isis_area *area;
|
||||
struct isis_circuit *circuit;
|
||||
|
||||
if (args->event != NB_EV_APPLY)
|
||||
return NB_OK;
|
||||
|
||||
circuit = nb_running_get_entry(args->dnode, NULL, true);
|
||||
circuit->rlfa_max_metric[1] = yang_dnode_get_uint32(args->dnode, NULL);
|
||||
|
||||
area = circuit->area;
|
||||
lsp_regenerate_schedule(area, area->is_type, 0);
|
||||
|
||||
return NB_OK;
|
||||
}
|
||||
|
||||
int lib_interface_isis_fast_reroute_level_2_remote_lfa_maximum_metric_destroy(
|
||||
struct nb_cb_destroy_args *args)
|
||||
{
|
||||
struct isis_area *area;
|
||||
struct isis_circuit *circuit;
|
||||
|
||||
if (args->event != NB_EV_APPLY)
|
||||
return NB_OK;
|
||||
|
||||
circuit = nb_running_get_entry(args->dnode, NULL, true);
|
||||
circuit->rlfa_max_metric[1] = 0;
|
||||
|
||||
area = circuit->area;
|
||||
lsp_regenerate_schedule(area, area->is_type, 0);
|
||||
|
||||
return NB_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
* XPath:
|
||||
* /frr-interface:lib/interface/frr-isisd:isis/fast-reroute/level-2/ti-lfa/enable
|
||||
|
@ -279,6 +279,22 @@ static bool isis_sr_psid_info_same(struct isis_sr_psid_info *new,
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool isis_label_stack_same(struct mpls_label_stack *new,
|
||||
struct mpls_label_stack *old)
|
||||
{
|
||||
if (!new && !old)
|
||||
return true;
|
||||
if (!new || !old)
|
||||
return false;
|
||||
if (new->num_labels != old->num_labels)
|
||||
return false;
|
||||
if (memcmp(&new->label, &old->label,
|
||||
sizeof(mpls_label_t) * new->num_labels))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static int isis_route_info_same(struct isis_route_info *new,
|
||||
struct isis_route_info *old, char *buf,
|
||||
size_t buf_size)
|
||||
@ -327,6 +343,12 @@ static int isis_route_info_same(struct isis_route_info *new,
|
||||
snprintf(buf, buf_size, "nhop SR label");
|
||||
return 0;
|
||||
}
|
||||
if (!isis_label_stack_same(new_nh->label_stack,
|
||||
old_nh->label_stack)) {
|
||||
if (buf)
|
||||
snprintf(buf, buf_size, "nhop label stack");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* only the resync flag needs to be checked */
|
||||
@ -400,8 +422,8 @@ isis_route_create(struct prefix *prefix, struct prefix_ipv6 *src_p,
|
||||
return route_info;
|
||||
}
|
||||
|
||||
static void isis_route_delete(struct isis_area *area, struct route_node *rode,
|
||||
struct route_table *table)
|
||||
void isis_route_delete(struct isis_area *area, struct route_node *rode,
|
||||
struct route_table *table)
|
||||
{
|
||||
struct isis_route_info *rinfo;
|
||||
char buff[SRCDEST2STR_BUFFER];
|
||||
@ -466,9 +488,6 @@ static void isis_route_update(struct isis_area *area, struct prefix *prefix,
|
||||
SET_FLAG(route_info->flag, ISIS_ROUTE_FLAG_ZEBRA_SYNCED);
|
||||
UNSET_FLAG(route_info->flag, ISIS_ROUTE_FLAG_ZEBRA_RESYNC);
|
||||
} else {
|
||||
if (!CHECK_FLAG(route_info->flag, ISIS_ROUTE_FLAG_ZEBRA_SYNCED))
|
||||
return;
|
||||
|
||||
/* Uninstall Prefix-SID label. */
|
||||
if (route_info->sr.present)
|
||||
isis_zebra_prefix_sid_uninstall(
|
||||
@ -516,6 +535,10 @@ static void _isis_route_verify_table(struct isis_area *area,
|
||||
rinfo->backup = rnode_bck->info;
|
||||
UNSET_FLAG(rinfo->flag,
|
||||
ISIS_ROUTE_FLAG_ZEBRA_SYNCED);
|
||||
} else if (rinfo->backup) {
|
||||
rinfo->backup = NULL;
|
||||
UNSET_FLAG(rinfo->flag,
|
||||
ISIS_ROUTE_FLAG_ZEBRA_SYNCED);
|
||||
}
|
||||
}
|
||||
|
||||
@ -629,6 +652,10 @@ void isis_route_verify_merge(struct isis_area *area,
|
||||
rinfo->backup = rnode_bck->info;
|
||||
UNSET_FLAG(rinfo->flag,
|
||||
ISIS_ROUTE_FLAG_ZEBRA_SYNCED);
|
||||
} else if (rinfo->backup) {
|
||||
rinfo->backup = NULL;
|
||||
UNSET_FLAG(rinfo->flag,
|
||||
ISIS_ROUTE_FLAG_ZEBRA_SYNCED);
|
||||
}
|
||||
|
||||
mrnode = srcdest_rnode_get(merge, prefix, src_p);
|
||||
|
@ -63,6 +63,8 @@ isis_route_create(struct prefix *prefix, struct prefix_ipv6 *src_p,
|
||||
uint32_t cost, uint32_t depth, struct isis_sr_psid_info *sr,
|
||||
struct list *adjacencies, bool allow_ecmp,
|
||||
struct isis_area *area, struct route_table *table);
|
||||
void isis_route_delete(struct isis_area *area, struct route_node *rode,
|
||||
struct route_table *table);
|
||||
|
||||
/* Walk the given table and install new routes to zebra and remove old ones.
|
||||
* route status is tracked using ISIS_ROUTE_FLAG_ACTIVE */
|
||||
|
@ -56,6 +56,7 @@
|
||||
#include "isis_csm.h"
|
||||
#include "isis_mt.h"
|
||||
#include "isis_tlvs.h"
|
||||
#include "isis_zebra.h"
|
||||
#include "fabricd.h"
|
||||
#include "isis_spf_private.h"
|
||||
|
||||
@ -354,7 +355,10 @@ struct isis_spftree *isis_spftree_new(struct isis_area *area,
|
||||
tree->tree_id = tree_id;
|
||||
tree->family = (tree->tree_id == SPFTREE_IPV4) ? AF_INET : AF_INET6;
|
||||
tree->flags = flags;
|
||||
if (tree->type == SPF_TYPE_TI_LFA) {
|
||||
isis_rlfa_list_init(tree);
|
||||
tree->lfa.remote.pc_spftrees = list_new();
|
||||
tree->lfa.remote.pc_spftrees->del = (void (*)(void *))isis_spftree_del;
|
||||
if (tree->type == SPF_TYPE_RLFA || tree->type == SPF_TYPE_TI_LFA) {
|
||||
isis_spf_node_list_init(&tree->lfa.p_space);
|
||||
isis_spf_node_list_init(&tree->lfa.q_space);
|
||||
}
|
||||
@ -366,7 +370,11 @@ void isis_spftree_del(struct isis_spftree *spftree)
|
||||
{
|
||||
hash_clean(spftree->prefix_sids, NULL);
|
||||
hash_free(spftree->prefix_sids);
|
||||
if (spftree->type == SPF_TYPE_TI_LFA) {
|
||||
isis_zebra_rlfa_unregister_all(spftree);
|
||||
isis_rlfa_list_clear(spftree);
|
||||
list_delete(&spftree->lfa.remote.pc_spftrees);
|
||||
if (spftree->type == SPF_TYPE_RLFA
|
||||
|| spftree->type == SPF_TYPE_TI_LFA) {
|
||||
isis_spf_node_list_clear(&spftree->lfa.q_space);
|
||||
isis_spf_node_list_clear(&spftree->lfa.p_space);
|
||||
}
|
||||
@ -1440,6 +1448,9 @@ static void init_spt(struct isis_spftree *spftree, int mtid)
|
||||
list_delete_all_node(spftree->sadj_list);
|
||||
isis_vertex_queue_clear(&spftree->tents);
|
||||
isis_vertex_queue_clear(&spftree->paths);
|
||||
isis_zebra_rlfa_unregister_all(spftree);
|
||||
isis_rlfa_list_clear(spftree);
|
||||
list_delete_all_node(spftree->lfa.remote.pc_spftrees);
|
||||
memset(&spftree->lfa.protection_counters, 0,
|
||||
sizeof(spftree->lfa.protection_counters));
|
||||
|
||||
@ -1513,12 +1524,13 @@ static void spf_path_process(struct isis_spftree *spftree,
|
||||
priority = spf_prefix_priority(spftree, vertex);
|
||||
vertex->N.ip.priority = priority;
|
||||
if (vertex->depth == 1 || listcount(vertex->Adj_N) > 0) {
|
||||
struct isis_spftree *pre_spftree;
|
||||
struct route_table *route_table;
|
||||
bool allow_ecmp;
|
||||
|
||||
if (spftree->type == SPF_TYPE_TI_LFA) {
|
||||
struct isis_spftree *pre_spftree;
|
||||
|
||||
switch (spftree->type) {
|
||||
case SPF_TYPE_RLFA:
|
||||
case SPF_TYPE_TI_LFA:
|
||||
if (priority
|
||||
> area->lfa_priority_limit[level - 1]) {
|
||||
if (IS_DEBUG_LFA)
|
||||
@ -1531,7 +1543,16 @@ static void spf_path_process(struct isis_spftree *spftree,
|
||||
sizeof(buff)));
|
||||
return;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
switch (spftree->type) {
|
||||
case SPF_TYPE_RLFA:
|
||||
isis_rlfa_check(spftree, vertex);
|
||||
return;
|
||||
case SPF_TYPE_TI_LFA:
|
||||
if (isis_tilfa_check(spftree, vertex) != 0)
|
||||
return;
|
||||
|
||||
@ -1540,7 +1561,8 @@ static void spf_path_process(struct isis_spftree *spftree,
|
||||
allow_ecmp = area->lfa_load_sharing[level - 1];
|
||||
pre_spftree->lfa.protection_counters
|
||||
.tilfa[vertex->N.ip.priority] += 1;
|
||||
} else {
|
||||
break;
|
||||
default:
|
||||
route_table = spftree->route_table;
|
||||
allow_ecmp = true;
|
||||
|
||||
@ -1555,6 +1577,7 @@ static void spf_path_process(struct isis_spftree *spftree,
|
||||
spftree->lfa.protection_counters
|
||||
.ecmp[priority] += 1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
isis_route_create(
|
||||
@ -1845,6 +1868,7 @@ int _isis_spf_schedule(struct isis_area *area, int level,
|
||||
area->area_tag, level, diff, func, file, line);
|
||||
}
|
||||
|
||||
thread_cancel(&area->t_rlfa_rib_update);
|
||||
if (area->spf_delay_ietf[level - 1]) {
|
||||
/* Need to call schedule function also if spf delay is running
|
||||
* to
|
||||
|
@ -31,6 +31,7 @@ struct isis_spftree;
|
||||
enum spf_type {
|
||||
SPF_TYPE_FORWARD = 1,
|
||||
SPF_TYPE_REVERSE,
|
||||
SPF_TYPE_RLFA,
|
||||
SPF_TYPE_TI_LFA,
|
||||
};
|
||||
|
||||
|
@ -76,7 +76,9 @@ struct isis_vertex {
|
||||
struct list *parents; /* list of parents for ECMP */
|
||||
struct hash *firsthops; /* first two hops to neighbor */
|
||||
uint64_t insert_counter;
|
||||
uint8_t flags;
|
||||
};
|
||||
#define F_ISIS_VERTEX_LFA_PROTECTED 0x01
|
||||
|
||||
/* Vertex Queue and associated functions */
|
||||
|
||||
@ -349,6 +351,21 @@ struct isis_spftree {
|
||||
struct isis_spf_nodes p_space;
|
||||
struct isis_spf_nodes q_space;
|
||||
|
||||
/* Remote LFA related information. */
|
||||
struct {
|
||||
/* List of RLFAs eligible to be installed. */
|
||||
struct rlfa_tree_head rlfas;
|
||||
|
||||
/*
|
||||
* RLFA post-convergence SPTs (needed to activate RLFAs
|
||||
* once label information is received from LDP).
|
||||
*/
|
||||
struct list *pc_spftrees;
|
||||
|
||||
/* RLFA maximum metric (or zero if absent). */
|
||||
uint32_t max_metric;
|
||||
} remote;
|
||||
|
||||
/* Protection counters. */
|
||||
struct {
|
||||
uint32_t lfa[SPF_PREFIX_PRIO_MAX];
|
||||
|
@ -47,6 +47,8 @@
|
||||
#include "isisd/isis_circuit.h"
|
||||
#include "isisd/isis_csm.h"
|
||||
#include "isisd/isis_lsp.h"
|
||||
#include "isisd/isis_spf.h"
|
||||
#include "isisd/isis_spf_private.h"
|
||||
#include "isisd/isis_route.h"
|
||||
#include "isisd/isis_zebra.h"
|
||||
#include "isisd/isis_adjacency.h"
|
||||
@ -540,6 +542,72 @@ void isis_zebra_redistribute_unset(afi_t afi, int type)
|
||||
type, 0, VRF_DEFAULT);
|
||||
}
|
||||
|
||||
/**
|
||||
* Register RLFA with LDP.
|
||||
*/
|
||||
int isis_zebra_rlfa_register(struct isis_spftree *spftree, struct rlfa *rlfa)
|
||||
{
|
||||
struct isis_area *area = spftree->area;
|
||||
struct zapi_rlfa_request zr = {};
|
||||
int ret;
|
||||
|
||||
if (!zclient)
|
||||
return 0;
|
||||
|
||||
zr.igp.vrf_id = area->isis->vrf_id;
|
||||
zr.igp.protocol = ZEBRA_ROUTE_ISIS;
|
||||
strlcpy(zr.igp.isis.area_tag, area->area_tag,
|
||||
sizeof(zr.igp.isis.area_tag));
|
||||
zr.igp.isis.spf.tree_id = spftree->tree_id;
|
||||
zr.igp.isis.spf.level = spftree->level;
|
||||
zr.igp.isis.spf.run_id = spftree->runcount;
|
||||
zr.destination = rlfa->prefix;
|
||||
zr.pq_address = rlfa->pq_address;
|
||||
|
||||
zlog_debug("ISIS-LFA: registering RLFA %pFX@%pI4 with LDP",
|
||||
&rlfa->prefix, &rlfa->pq_address);
|
||||
|
||||
ret = zclient_send_opaque_unicast(zclient, LDP_RLFA_REGISTER,
|
||||
ZEBRA_ROUTE_LDP, 0, 0,
|
||||
(const uint8_t *)&zr, sizeof(zr));
|
||||
if (ret == ZCLIENT_SEND_FAILURE) {
|
||||
zlog_warn("ISIS-LFA: failed to register RLFA with LDP");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Unregister all RLFAs from the given SPF tree with LDP.
|
||||
*/
|
||||
void isis_zebra_rlfa_unregister_all(struct isis_spftree *spftree)
|
||||
{
|
||||
struct isis_area *area = spftree->area;
|
||||
struct zapi_rlfa_igp igp = {};
|
||||
int ret;
|
||||
|
||||
if (!zclient || spftree->type != SPF_TYPE_FORWARD
|
||||
|| CHECK_FLAG(spftree->flags, F_SPFTREE_NO_ADJACENCIES))
|
||||
return;
|
||||
|
||||
if (IS_DEBUG_LFA)
|
||||
zlog_debug("ISIS-LFA: unregistering all RLFAs with LDP");
|
||||
|
||||
igp.vrf_id = area->isis->vrf_id;
|
||||
igp.protocol = ZEBRA_ROUTE_ISIS;
|
||||
strlcpy(igp.isis.area_tag, area->area_tag, sizeof(igp.isis.area_tag));
|
||||
igp.isis.spf.tree_id = spftree->tree_id;
|
||||
igp.isis.spf.level = spftree->level;
|
||||
igp.isis.spf.run_id = spftree->runcount;
|
||||
|
||||
ret = zclient_send_opaque_unicast(zclient, LDP_RLFA_UNREGISTER_ALL,
|
||||
ZEBRA_ROUTE_LDP, 0, 0,
|
||||
(const uint8_t *)&igp, sizeof(igp));
|
||||
if (ret == ZCLIENT_SEND_FAILURE)
|
||||
zlog_warn("ISIS-LFA: failed to unregister RLFA with LDP");
|
||||
}
|
||||
|
||||
/* Label Manager Functions */
|
||||
|
||||
/**
|
||||
@ -659,6 +727,7 @@ void isis_zebra_vrf_register(struct isis *isis)
|
||||
static void isis_zebra_connected(struct zclient *zclient)
|
||||
{
|
||||
zclient_send_reg_requests(zclient, VRF_DEFAULT);
|
||||
zclient_register_opaque(zclient, LDP_RLFA_LABELS);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -670,6 +739,7 @@ static int isis_opaque_msg_handler(ZAPI_CALLBACK_ARGS)
|
||||
struct zapi_opaque_msg info;
|
||||
struct ldp_igp_sync_if_state state;
|
||||
struct ldp_igp_sync_announce announce;
|
||||
struct zapi_rlfa_response rlfa;
|
||||
int ret = 0;
|
||||
|
||||
s = zclient->ibuf;
|
||||
@ -685,6 +755,10 @@ static int isis_opaque_msg_handler(ZAPI_CALLBACK_ARGS)
|
||||
STREAM_GET(&announce, s, sizeof(announce));
|
||||
ret = isis_ldp_sync_announce_update(announce);
|
||||
break;
|
||||
case LDP_RLFA_LABELS:
|
||||
STREAM_GET(&rlfa, s, sizeof(rlfa));
|
||||
isis_rlfa_process_ldp_response(&rlfa);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@ -704,6 +778,7 @@ static int isis_zebra_client_close_notify(ZAPI_CALLBACK_ARGS)
|
||||
return -1;
|
||||
|
||||
isis_ldp_sync_handle_client_close(&info);
|
||||
isis_ldp_rlfa_handle_client_close(&info);
|
||||
|
||||
return ret;
|
||||
}
|
||||
@ -742,6 +817,7 @@ void isis_zebra_init(struct thread_master *master, int instance)
|
||||
|
||||
void isis_zebra_stop(void)
|
||||
{
|
||||
zclient_unregister_opaque(zclient, LDP_RLFA_LABELS);
|
||||
zclient_stop(zclient_sync);
|
||||
zclient_free(zclient_sync);
|
||||
zclient_stop(zclient);
|
||||
|
@ -59,6 +59,8 @@ void isis_zebra_send_adjacency_sid(int cmd, const struct sr_adjacency *sra);
|
||||
int isis_distribute_list_update(int routetype);
|
||||
void isis_zebra_redistribute_set(afi_t afi, int type);
|
||||
void isis_zebra_redistribute_unset(afi_t afi, int type);
|
||||
int isis_zebra_rlfa_register(struct isis_spftree *spftree, struct rlfa *rlfa);
|
||||
void isis_zebra_rlfa_unregister_all(struct isis_spftree *spftree);
|
||||
bool isis_zebra_label_manager_ready(void);
|
||||
int isis_zebra_label_manager_connect(void);
|
||||
int isis_zebra_request_label_range(uint32_t base, uint32_t chunk_size);
|
||||
|
@ -32,6 +32,7 @@
|
||||
#include "if.h"
|
||||
#include "hash.h"
|
||||
#include "filter.h"
|
||||
#include "plist.h"
|
||||
#include "stream.h"
|
||||
#include "prefix.h"
|
||||
#include "table.h"
|
||||
@ -485,6 +486,7 @@ void isis_area_destroy(struct isis_area *area)
|
||||
thread_cancel(&area->t_tick);
|
||||
thread_cancel(&area->t_lsp_refresh[0]);
|
||||
thread_cancel(&area->t_lsp_refresh[1]);
|
||||
thread_cancel(&area->t_rlfa_rib_update);
|
||||
|
||||
thread_cancel_event(master, area);
|
||||
|
||||
@ -649,6 +651,34 @@ void isis_filter_update(struct access_list *access)
|
||||
}
|
||||
}
|
||||
|
||||
void isis_prefix_list_update(struct prefix_list *plist)
|
||||
{
|
||||
struct isis *isis;
|
||||
struct isis_area *area;
|
||||
struct listnode *node, *anode;
|
||||
|
||||
for (ALL_LIST_ELEMENTS_RO(im->isis, node, isis)) {
|
||||
for (ALL_LIST_ELEMENTS_RO(isis->area_list, anode, area)) {
|
||||
for (int level = ISIS_LEVEL1; level <= ISIS_LEVELS;
|
||||
level++) {
|
||||
const char *plist_name =
|
||||
prefix_list_name(plist);
|
||||
|
||||
if (!area->rlfa_plist_name[level - 1])
|
||||
continue;
|
||||
|
||||
if (!strmatch(area->rlfa_plist_name[level - 1],
|
||||
plist_name))
|
||||
continue;
|
||||
|
||||
area->rlfa_plist[level - 1] =
|
||||
prefix_list_lookup(AFI_IP, plist_name);
|
||||
lsp_regenerate_schedule(area, area->is_type, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef FABRICD
|
||||
static void area_set_mt_enabled(struct isis_area *area, uint16_t mtid,
|
||||
bool enabled)
|
||||
|
@ -131,6 +131,7 @@ struct isis_area {
|
||||
struct thread *t_tick; /* LSP walker */
|
||||
struct thread *t_lsp_refresh[ISIS_LEVELS];
|
||||
struct timeval last_lsp_refresh_event[ISIS_LEVELS];
|
||||
struct thread *t_rlfa_rib_update;
|
||||
/* t_lsp_refresh is used in two ways:
|
||||
* a) regular refresh of LSPs
|
||||
* b) (possibly throttled) updates to LSPs
|
||||
@ -197,6 +198,9 @@ struct isis_area {
|
||||
size_t lfa_load_sharing[ISIS_LEVELS];
|
||||
enum spf_prefix_priority lfa_priority_limit[ISIS_LEVELS];
|
||||
struct lfa_tiebreaker_tree_head lfa_tiebreakers[ISIS_LEVELS];
|
||||
char *rlfa_plist_name[ISIS_LEVELS];
|
||||
struct prefix_list *rlfa_plist[ISIS_LEVELS];
|
||||
size_t rlfa_protected_links[ISIS_LEVELS];
|
||||
size_t tilfa_protected_links[ISIS_LEVELS];
|
||||
/* Counters */
|
||||
uint32_t circuit_state_changes;
|
||||
@ -240,6 +244,7 @@ struct isis_area *isis_area_lookup_by_vrf(const char *area_tag,
|
||||
int isis_area_get(struct vty *vty, const char *area_tag);
|
||||
void isis_area_destroy(struct isis_area *area);
|
||||
void isis_filter_update(struct access_list *access);
|
||||
void isis_prefix_list_update(struct prefix_list *plist);
|
||||
void print_debug(struct vty *, int, int);
|
||||
struct isis_lsp *lsp_for_arg(struct lspdb_head *head, const char *argv,
|
||||
struct isis *isis);
|
||||
|
@ -183,7 +183,8 @@ adj_itimer(struct thread *thread)
|
||||
|
||||
if (adj->source.type == HELLO_TARGETED) {
|
||||
if (!(adj->source.target->flags & F_TNBR_CONFIGURED) &&
|
||||
adj->source.target->pw_count == 0) {
|
||||
adj->source.target->pw_count == 0 &&
|
||||
adj->source.target->rlfa_count == 0) {
|
||||
/* remove dynamic targeted neighbor */
|
||||
tnbr_del(leconf, adj->source.target);
|
||||
return (0);
|
||||
@ -259,7 +260,7 @@ struct tnbr *
|
||||
tnbr_check(struct ldpd_conf *xconf, struct tnbr *tnbr)
|
||||
{
|
||||
if (!(tnbr->flags & (F_TNBR_CONFIGURED|F_TNBR_DYNAMIC)) &&
|
||||
tnbr->pw_count == 0) {
|
||||
tnbr->pw_count == 0 && tnbr->rlfa_count == 0) {
|
||||
tnbr_del(xconf, tnbr);
|
||||
return (NULL);
|
||||
}
|
||||
|
@ -67,7 +67,8 @@ send_hello(enum hello_type type, struct iface_af *ia, struct tnbr *tnbr)
|
||||
af = tnbr->af;
|
||||
holdtime = tnbr_get_hello_holdtime(tnbr);
|
||||
flags = F_HELLO_TARGETED;
|
||||
if ((tnbr->flags & F_TNBR_CONFIGURED) || tnbr->pw_count)
|
||||
if ((tnbr->flags & F_TNBR_CONFIGURED) || tnbr->pw_count
|
||||
|| tnbr->rlfa_count)
|
||||
flags |= F_HELLO_REQ_TARG;
|
||||
fd = (ldp_af_global_get(&global, af))->ldp_edisc_socket;
|
||||
|
||||
|
86
ldpd/lde.c
86
ldpd/lde.c
@ -27,6 +27,7 @@
|
||||
#include "log.h"
|
||||
#include "lde.h"
|
||||
#include "ldp_debug.h"
|
||||
#include "rlfa.h"
|
||||
|
||||
#include <lib/log.h>
|
||||
#include "memory.h"
|
||||
@ -444,6 +445,10 @@ lde_dispatch_parent(struct thread *thread)
|
||||
int shut = 0;
|
||||
struct fec fec;
|
||||
struct ldp_access *laccess;
|
||||
struct ldp_rlfa_node *rnode, *rntmp;
|
||||
struct ldp_rlfa_client *rclient;
|
||||
struct zapi_rlfa_request *rlfa_req;
|
||||
struct zapi_rlfa_igp *rlfa_igp;
|
||||
|
||||
iev->ev_read = NULL;
|
||||
|
||||
@ -650,6 +655,42 @@ lde_dispatch_parent(struct thread *thread)
|
||||
lde_check_filter_af(AF_INET6, &ldeconf->ipv6,
|
||||
laccess->name);
|
||||
break;
|
||||
case IMSG_RLFA_REG:
|
||||
if (imsg.hdr.len != IMSG_HEADER_SIZE +
|
||||
sizeof(struct zapi_rlfa_request)) {
|
||||
log_warnx("%s: wrong imsg len", __func__);
|
||||
break;
|
||||
}
|
||||
rlfa_req = imsg.data;
|
||||
rnode = rlfa_node_find(&rlfa_req->destination,
|
||||
rlfa_req->pq_address);
|
||||
if (!rnode)
|
||||
rnode = rlfa_node_new(&rlfa_req->destination,
|
||||
rlfa_req->pq_address);
|
||||
rclient = rlfa_client_find(rnode, &rlfa_req->igp);
|
||||
if (rclient)
|
||||
/* RLFA already registered - do nothing */
|
||||
break;
|
||||
rclient = rlfa_client_new(rnode, &rlfa_req->igp);
|
||||
lde_rlfa_check(rclient);
|
||||
break;
|
||||
case IMSG_RLFA_UNREG_ALL:
|
||||
if (imsg.hdr.len != IMSG_HEADER_SIZE +
|
||||
sizeof(struct zapi_rlfa_igp)) {
|
||||
log_warnx("%s: wrong imsg len", __func__);
|
||||
break;
|
||||
}
|
||||
rlfa_igp = imsg.data;
|
||||
|
||||
RB_FOREACH_SAFE (rnode, ldp_rlfa_node_head,
|
||||
&rlfa_node_tree, rntmp) {
|
||||
rclient = rlfa_client_find(rnode, rlfa_igp);
|
||||
if (!rclient)
|
||||
continue;
|
||||
|
||||
rlfa_client_del(rclient);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
log_debug("%s: unexpected imsg %d", __func__,
|
||||
imsg.hdr.type);
|
||||
@ -875,6 +916,48 @@ lde_send_delete_klabel(struct fec_node *fn, struct fec_nh *fnh)
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
lde_fec2prefix(const struct fec *fec, struct prefix *prefix)
|
||||
{
|
||||
memset(prefix, 0, sizeof(*prefix));
|
||||
switch (fec->type) {
|
||||
case FEC_TYPE_IPV4:
|
||||
prefix->family = AF_INET;
|
||||
prefix->u.prefix4 = fec->u.ipv4.prefix;
|
||||
prefix->prefixlen = fec->u.ipv4.prefixlen;
|
||||
break;
|
||||
case FEC_TYPE_IPV6:
|
||||
prefix->family = AF_INET6;
|
||||
prefix->u.prefix6 = fec->u.ipv6.prefix;
|
||||
prefix->prefixlen = fec->u.ipv6.prefixlen;
|
||||
break;
|
||||
default:
|
||||
prefix->family = AF_UNSPEC;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
lde_prefix2fec(const struct prefix *prefix, struct fec *fec)
|
||||
{
|
||||
memset(fec, 0, sizeof(*fec));
|
||||
switch (prefix->family) {
|
||||
case AF_INET:
|
||||
fec->type = FEC_TYPE_IPV4;
|
||||
fec->u.ipv4.prefix = prefix->u.prefix4;
|
||||
fec->u.ipv4.prefixlen = prefix->prefixlen;
|
||||
break;
|
||||
case AF_INET6:
|
||||
fec->type = FEC_TYPE_IPV6;
|
||||
fec->u.ipv6.prefix = prefix->u.prefix6;
|
||||
fec->u.ipv6.prefixlen = prefix->prefixlen;
|
||||
break;
|
||||
default:
|
||||
fatalx("lde_prefix2fec: unknown af");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
lde_fec2map(struct fec *fec, struct map *map)
|
||||
{
|
||||
@ -1388,6 +1471,9 @@ lde_nbr_del(struct lde_nbr *ln)
|
||||
RB_FOREACH(f, fec_tree, &ft) {
|
||||
fn = (struct fec_node *)f;
|
||||
|
||||
/* Update RLFA clients. */
|
||||
lde_rlfa_update_clients(f, ln, MPLS_INVALID_LABEL);
|
||||
|
||||
LIST_FOREACH(fnh, &fn->nexthops, entry) {
|
||||
switch (f->type) {
|
||||
case FEC_TYPE_IPV4:
|
||||
|
@ -129,7 +129,9 @@ struct fec_node {
|
||||
uint32_t pw_remote_status;
|
||||
|
||||
void *data; /* fec specific data */
|
||||
uint8_t flags;
|
||||
};
|
||||
#define F_FEC_NHS_CHANGED 0x01
|
||||
|
||||
#define CHUNK_SIZE 64
|
||||
struct label_chunk {
|
||||
@ -156,6 +158,8 @@ uint32_t lde_update_label(struct fec_node *);
|
||||
void lde_free_label(uint32_t label);
|
||||
void lde_send_change_klabel(struct fec_node *, struct fec_nh *);
|
||||
void lde_send_delete_klabel(struct fec_node *, struct fec_nh *);
|
||||
void lde_fec2prefix(const struct fec *fec, struct prefix *prefix);
|
||||
void lde_prefix2fec(const struct prefix *prefix, struct fec *fec);
|
||||
void lde_fec2map(struct fec *, struct map *);
|
||||
void lde_map2fec(struct map *, struct in_addr, struct fec *);
|
||||
void lde_send_labelmapping(struct lde_nbr *, struct fec_node *,
|
||||
|
@ -23,6 +23,7 @@
|
||||
#include "ldpe.h"
|
||||
#include "lde.h"
|
||||
#include "log.h"
|
||||
#include "rlfa.h"
|
||||
|
||||
#include "mpls.h"
|
||||
|
||||
@ -339,6 +340,8 @@ lde_kernel_insert(struct fec *fec, int af, union ldpd_addr *nexthop,
|
||||
|
||||
fnh = fec_nh_find(fn, af, nexthop, ifindex, route_type, route_instance);
|
||||
if (fnh == NULL) {
|
||||
fn->flags |= F_FEC_NHS_CHANGED;
|
||||
|
||||
fnh = fec_nh_add(fn, af, nexthop, ifindex, route_type,
|
||||
route_instance);
|
||||
/*
|
||||
@ -415,11 +418,17 @@ lde_kernel_update(struct fec *fec)
|
||||
} else
|
||||
fnh->flags |= F_FEC_NH_NO_LDP;
|
||||
} else {
|
||||
fn->flags |= F_FEC_NHS_CHANGED;
|
||||
lde_send_delete_klabel(fn, fnh);
|
||||
fec_nh_del(fnh);
|
||||
}
|
||||
}
|
||||
|
||||
if (!(fn->flags & F_FEC_NHS_CHANGED))
|
||||
/* return earlier if nothing has changed */
|
||||
return;
|
||||
fn->flags &= ~F_FEC_NHS_CHANGED;
|
||||
|
||||
if (LIST_EMPTY(&fn->nexthops)) {
|
||||
RB_FOREACH(ln, nbr_tree, &lde_nbrs)
|
||||
lde_send_labelwithdraw(ln, fn, NULL, NULL);
|
||||
@ -601,6 +610,10 @@ lde_check_mapping(struct map *map, struct lde_nbr *ln, int rcvd_label_mapping)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Update RLFA clients. */
|
||||
lde_rlfa_update_clients(&fec, ln, map->label);
|
||||
|
||||
/* LMp.13 & LMp.16: Record the mapping from this peer */
|
||||
if (me == NULL)
|
||||
me = lde_map_add(ln, fn, 0);
|
||||
@ -858,6 +871,9 @@ lde_check_withdraw(struct map *map, struct lde_nbr *ln)
|
||||
fnh->remote_label = NO_LABEL;
|
||||
}
|
||||
|
||||
/* Update RLFA clients. */
|
||||
lde_rlfa_update_clients(&fec, ln, MPLS_INVALID_LABEL);
|
||||
|
||||
/* LWd.2: send label release */
|
||||
lde_send_labelrelease(ln, fn, NULL, map->label);
|
||||
|
||||
@ -940,6 +956,9 @@ lde_check_withdraw_wcard(struct map *map, struct lde_nbr *ln)
|
||||
fnh->remote_label = NO_LABEL;
|
||||
}
|
||||
|
||||
/* Update RLFA clients. */
|
||||
lde_rlfa_update_clients(f, ln, MPLS_INVALID_LABEL);
|
||||
|
||||
/* LWd.3: check previously received label mapping */
|
||||
if (me && (map->label == NO_LABEL ||
|
||||
map->label == me->map.label))
|
||||
|
@ -114,12 +114,16 @@ static void
|
||||
ldp_zebra_opaque_register(void)
|
||||
{
|
||||
zclient_register_opaque(zclient, LDP_IGP_SYNC_IF_STATE_REQUEST);
|
||||
zclient_register_opaque(zclient, LDP_RLFA_REGISTER);
|
||||
zclient_register_opaque(zclient, LDP_RLFA_UNREGISTER_ALL);
|
||||
}
|
||||
|
||||
static void
|
||||
ldp_zebra_opaque_unregister(void)
|
||||
{
|
||||
zclient_unregister_opaque(zclient, LDP_IGP_SYNC_IF_STATE_REQUEST);
|
||||
zclient_unregister_opaque(zclient, LDP_RLFA_REGISTER);
|
||||
zclient_unregister_opaque(zclient, LDP_RLFA_UNREGISTER_ALL);
|
||||
}
|
||||
|
||||
int
|
||||
@ -147,12 +151,29 @@ ldp_sync_zebra_send_announce(void)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ldp_zebra_send_rlfa_labels(struct zapi_rlfa_response *rlfa_labels)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = zclient_send_opaque(zclient, LDP_RLFA_LABELS,
|
||||
(const uint8_t *)rlfa_labels,
|
||||
sizeof(*rlfa_labels));
|
||||
if (ret == ZCLIENT_SEND_FAILURE) {
|
||||
log_warn("failed to send RLFA labels to IGP");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
ldp_zebra_opaque_msg_handler(ZAPI_CALLBACK_ARGS)
|
||||
{
|
||||
struct stream *s;
|
||||
struct zapi_opaque_msg info;
|
||||
struct ldp_igp_sync_if_state_req state_req;
|
||||
struct zapi_rlfa_igp igp;
|
||||
struct zapi_rlfa_request rlfa;
|
||||
|
||||
s = zclient->ibuf;
|
||||
|
||||
@ -165,6 +186,14 @@ ldp_zebra_opaque_msg_handler(ZAPI_CALLBACK_ARGS)
|
||||
main_imsg_compose_ldpe(IMSG_LDP_SYNC_IF_STATE_REQUEST, 0, &state_req,
|
||||
sizeof(state_req));
|
||||
break;
|
||||
case LDP_RLFA_REGISTER:
|
||||
STREAM_GET(&rlfa, s, sizeof(rlfa));
|
||||
main_imsg_compose_both(IMSG_RLFA_REG, &rlfa, sizeof(rlfa));
|
||||
break;
|
||||
case LDP_RLFA_UNREGISTER_ALL:
|
||||
STREAM_GET(&igp, s, sizeof(igp));
|
||||
main_imsg_compose_both(IMSG_RLFA_UNREG_ALL, &igp, sizeof(igp));
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
10
ldpd/ldpd.c
10
ldpd/ldpd.c
@ -625,6 +625,7 @@ main_dispatch_lde(struct thread *thread)
|
||||
struct imsg imsg;
|
||||
ssize_t n;
|
||||
int shut = 0;
|
||||
struct zapi_rlfa_response *rlfa_labels;
|
||||
|
||||
iev->ev_read = NULL;
|
||||
|
||||
@ -691,6 +692,15 @@ main_dispatch_lde(struct thread *thread)
|
||||
fatalx("IMSG_ACL_CHECK imsg with wrong len");
|
||||
ldp_acl_reply(iev, (struct acl_check *)imsg.data);
|
||||
break;
|
||||
case IMSG_RLFA_LABELS:
|
||||
if (imsg.hdr.len != IMSG_HEADER_SIZE +
|
||||
sizeof(struct zapi_rlfa_response)) {
|
||||
log_warnx("%s: wrong imsg len", __func__);
|
||||
break;
|
||||
}
|
||||
rlfa_labels = imsg.data;
|
||||
ldp_zebra_send_rlfa_labels(rlfa_labels);
|
||||
break;
|
||||
default:
|
||||
log_debug("%s: error handling imsg %d", __func__,
|
||||
imsg.hdr.type);
|
||||
|
@ -157,7 +157,10 @@ enum imsg_type {
|
||||
IMSG_FILTER_UPDATE,
|
||||
IMSG_NBR_SHUTDOWN,
|
||||
IMSG_LDP_SYNC_IF_STATE_REQUEST,
|
||||
IMSG_LDP_SYNC_IF_STATE_UPDATE
|
||||
IMSG_LDP_SYNC_IF_STATE_UPDATE,
|
||||
IMSG_RLFA_REG,
|
||||
IMSG_RLFA_UNREG_ALL,
|
||||
IMSG_RLFA_LABELS,
|
||||
};
|
||||
|
||||
struct ldpd_init {
|
||||
@ -373,6 +376,7 @@ struct tnbr {
|
||||
union ldpd_addr addr;
|
||||
int state;
|
||||
uint16_t pw_count;
|
||||
uint32_t rlfa_count;
|
||||
uint8_t flags;
|
||||
QOBJ_FIELDS
|
||||
};
|
||||
@ -875,6 +879,8 @@ extern char ctl_sock_path[MAXPATHLEN];
|
||||
void ldp_zebra_init(struct thread_master *);
|
||||
void ldp_zebra_destroy(void);
|
||||
int ldp_sync_zebra_send_state_update(struct ldp_igp_sync_if_state *);
|
||||
int ldp_zebra_send_rlfa_labels(struct zapi_rlfa_response *
|
||||
rlfa_labels);
|
||||
|
||||
/* compatibility */
|
||||
#ifndef __OpenBSD__
|
||||
|
45
ldpd/ldpe.c
45
ldpd/ldpe.c
@ -27,6 +27,7 @@
|
||||
#include "control.h"
|
||||
#include "log.h"
|
||||
#include "ldp_debug.h"
|
||||
#include "rlfa.h"
|
||||
|
||||
#include <lib/log.h>
|
||||
#include "memory.h"
|
||||
@ -298,7 +299,11 @@ ldpe_dispatch_main(struct thread *thread)
|
||||
int n, shut = 0;
|
||||
struct ldp_access *laccess;
|
||||
struct ldp_igp_sync_if_state_req *ldp_sync_if_state_req;
|
||||
|
||||
struct ldp_rlfa_node *rnode, *rntmp;
|
||||
struct ldp_rlfa_client *rclient;
|
||||
struct zapi_rlfa_request *rlfa_req;
|
||||
struct zapi_rlfa_igp *rlfa_igp;
|
||||
|
||||
iev->ev_read = NULL;
|
||||
|
||||
if ((n = imsg_read(ibuf)) == -1 && errno != EAGAIN)
|
||||
@ -569,6 +574,44 @@ ldpe_dispatch_main(struct thread *thread)
|
||||
ldp_sync_if_state_req = imsg.data;
|
||||
ldp_sync_fsm_state_req(ldp_sync_if_state_req);
|
||||
break;
|
||||
case IMSG_RLFA_REG:
|
||||
if (imsg.hdr.len != IMSG_HEADER_SIZE +
|
||||
sizeof(struct zapi_rlfa_request)) {
|
||||
log_warnx("%s: wrong imsg len", __func__);
|
||||
break;
|
||||
}
|
||||
rlfa_req = imsg.data;
|
||||
|
||||
rnode = rlfa_node_find(&rlfa_req->destination,
|
||||
rlfa_req->pq_address);
|
||||
if (!rnode)
|
||||
rnode = rlfa_node_new(&rlfa_req->destination,
|
||||
rlfa_req->pq_address);
|
||||
rclient = rlfa_client_find(rnode, &rlfa_req->igp);
|
||||
if (rclient)
|
||||
/* RLFA already registered - do nothing */
|
||||
break;
|
||||
rclient = rlfa_client_new(rnode, &rlfa_req->igp);
|
||||
ldpe_rlfa_init(rclient);
|
||||
break;
|
||||
case IMSG_RLFA_UNREG_ALL:
|
||||
if (imsg.hdr.len != IMSG_HEADER_SIZE +
|
||||
sizeof(struct zapi_rlfa_igp)) {
|
||||
log_warnx("%s: wrong imsg len", __func__);
|
||||
break;
|
||||
}
|
||||
rlfa_igp = imsg.data;
|
||||
|
||||
RB_FOREACH_SAFE (rnode, ldp_rlfa_node_head,
|
||||
&rlfa_node_tree, rntmp) {
|
||||
rclient = rlfa_client_find(rnode, rlfa_igp);
|
||||
if (!rclient)
|
||||
continue;
|
||||
|
||||
ldpe_rlfa_exit(rclient);
|
||||
rlfa_client_del(rclient);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
log_debug("ldpe_dispatch_main: error handling imsg %d",
|
||||
imsg.hdr.type);
|
||||
|
288
ldpd/rlfa.c
Normal file
288
ldpd/rlfa.c
Normal file
@ -0,0 +1,288 @@
|
||||
/*
|
||||
* Copyright (C) 2020 NetDEF, Inc.
|
||||
* Renato Westphal
|
||||
*
|
||||
* 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 "ldpd.h"
|
||||
#include "lde.h"
|
||||
#include "ldpe.h"
|
||||
#include "log.h"
|
||||
#include "ldp_debug.h"
|
||||
#include "rlfa.h"
|
||||
|
||||
#include <lib/log.h>
|
||||
|
||||
struct ldp_rlfa_node_head rlfa_node_tree;
|
||||
|
||||
static int ldp_rlfa_client_compare(const struct ldp_rlfa_client *a,
|
||||
const struct ldp_rlfa_client *b)
|
||||
{
|
||||
if (a->igp.vrf_id < b->igp.vrf_id)
|
||||
return -1;
|
||||
if (a->igp.vrf_id > b->igp.vrf_id)
|
||||
return 1;
|
||||
|
||||
if (a->igp.protocol < b->igp.protocol)
|
||||
return -1;
|
||||
if (a->igp.protocol > b->igp.protocol)
|
||||
return 1;
|
||||
|
||||
if (a->igp.isis.spf.tree_id < b->igp.isis.spf.tree_id)
|
||||
return -1;
|
||||
if (a->igp.isis.spf.tree_id > b->igp.isis.spf.tree_id)
|
||||
return 1;
|
||||
|
||||
if (a->igp.isis.spf.level < b->igp.isis.spf.level)
|
||||
return -1;
|
||||
if (a->igp.isis.spf.level > b->igp.isis.spf.level)
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
RB_GENERATE(ldp_rlfa_client_head, ldp_rlfa_client, entry,
|
||||
ldp_rlfa_client_compare)
|
||||
|
||||
static int ldp_rlfa_node_compare(const struct ldp_rlfa_node *a,
|
||||
const struct ldp_rlfa_node *b)
|
||||
{
|
||||
if (ntohl(a->pq_address.s_addr) < ntohl(b->pq_address.s_addr))
|
||||
return -1;
|
||||
if (ntohl(a->pq_address.s_addr) > ntohl(b->pq_address.s_addr))
|
||||
return 1;
|
||||
|
||||
return prefix_cmp(&a->destination, &b->destination);
|
||||
}
|
||||
RB_GENERATE(ldp_rlfa_node_head, ldp_rlfa_node, entry, ldp_rlfa_node_compare)
|
||||
|
||||
struct ldp_rlfa_client *rlfa_client_new(struct ldp_rlfa_node *rnode,
|
||||
struct zapi_rlfa_igp *igp)
|
||||
{
|
||||
struct ldp_rlfa_client *rclient;
|
||||
|
||||
if ((rclient = calloc(1, sizeof(*rclient))) == NULL)
|
||||
fatal(__func__);
|
||||
|
||||
rclient->igp = *igp;
|
||||
rclient->node = rnode;
|
||||
RB_INSERT(ldp_rlfa_client_head, &rnode->clients, rclient);
|
||||
|
||||
return rclient;
|
||||
}
|
||||
|
||||
void rlfa_client_del(struct ldp_rlfa_client *rclient)
|
||||
{
|
||||
struct ldp_rlfa_node *rnode = rclient->node;
|
||||
|
||||
RB_REMOVE(ldp_rlfa_client_head, &rnode->clients, rclient);
|
||||
free(rclient);
|
||||
|
||||
/* Delete RLFA node if it's empty. */
|
||||
if (RB_EMPTY(ldp_rlfa_client_head, &rnode->clients))
|
||||
rlfa_node_del(rnode);
|
||||
}
|
||||
|
||||
struct ldp_rlfa_client *rlfa_client_find(struct ldp_rlfa_node *rnode,
|
||||
struct zapi_rlfa_igp *igp)
|
||||
{
|
||||
struct ldp_rlfa_client rclient;
|
||||
|
||||
rclient.igp = *igp;
|
||||
return RB_FIND(ldp_rlfa_client_head, &rnode->clients, &rclient);
|
||||
}
|
||||
|
||||
struct ldp_rlfa_node *rlfa_node_new(const struct prefix *destination,
|
||||
struct in_addr pq_address)
|
||||
{
|
||||
struct ldp_rlfa_node *rnode;
|
||||
|
||||
if ((rnode = calloc(1, sizeof(*rnode))) == NULL)
|
||||
fatal(__func__);
|
||||
|
||||
rnode->destination = *destination;
|
||||
rnode->pq_address = pq_address;
|
||||
rnode->pq_label = MPLS_INVALID_LABEL;
|
||||
RB_INIT(ldp_rlfa_client_head, &rnode->clients);
|
||||
RB_INSERT(ldp_rlfa_node_head, &rlfa_node_tree, rnode);
|
||||
|
||||
return rnode;
|
||||
}
|
||||
|
||||
void rlfa_node_del(struct ldp_rlfa_node *rnode)
|
||||
{
|
||||
/* Delete RLFA clients. */
|
||||
while (!RB_EMPTY(ldp_rlfa_client_head, &rnode->clients)) {
|
||||
struct ldp_rlfa_client *rclient;
|
||||
|
||||
rclient = RB_ROOT(ldp_rlfa_client_head, &rnode->clients);
|
||||
rlfa_client_del(rclient);
|
||||
}
|
||||
|
||||
RB_REMOVE(ldp_rlfa_node_head, &rlfa_node_tree, rnode);
|
||||
free(rnode);
|
||||
}
|
||||
|
||||
struct ldp_rlfa_node *rlfa_node_find(const struct prefix *destination,
|
||||
struct in_addr pq_address)
|
||||
{
|
||||
struct ldp_rlfa_node rnode = {};
|
||||
|
||||
rnode.destination = *destination;
|
||||
rnode.pq_address = pq_address;
|
||||
return RB_FIND(ldp_rlfa_node_head, &rlfa_node_tree, &rnode);
|
||||
}
|
||||
|
||||
void lde_rlfa_client_send(struct ldp_rlfa_client *rclient)
|
||||
{
|
||||
struct ldp_rlfa_node *rnode = rclient->node;
|
||||
struct zapi_rlfa_response rlfa_labels = {};
|
||||
struct fec fec;
|
||||
struct fec_node *fn;
|
||||
struct fec_nh *fnh;
|
||||
int i = 0;
|
||||
|
||||
/* Fill in inner label (allocated by PQ node). */
|
||||
rlfa_labels.igp = rclient->igp;
|
||||
rlfa_labels.destination = rnode->destination;
|
||||
rlfa_labels.pq_label = rnode->pq_label;
|
||||
|
||||
/* Fill in outer label(s) (allocated by the nexthop routers). */
|
||||
fec.type = FEC_TYPE_IPV4;
|
||||
fec.u.ipv4.prefix = rnode->pq_address;
|
||||
fec.u.ipv4.prefixlen = IPV4_MAX_BITLEN;
|
||||
fn = (struct fec_node *)fec_find(&ft, &fec);
|
||||
if (!fn)
|
||||
return;
|
||||
LIST_FOREACH(fnh, &fn->nexthops, entry) {
|
||||
if (fnh->remote_label == NO_LABEL)
|
||||
continue;
|
||||
|
||||
rlfa_labels.nexthops[i].family = fnh->af;
|
||||
switch (fnh->af) {
|
||||
case AF_INET:
|
||||
rlfa_labels.nexthops[i].gate.ipv4 = fnh->nexthop.v4;
|
||||
break;
|
||||
case AF_INET6:
|
||||
rlfa_labels.nexthops[i].gate.ipv6 = fnh->nexthop.v6;
|
||||
break;
|
||||
default:
|
||||
continue;
|
||||
}
|
||||
rlfa_labels.nexthops[i].label = fnh->remote_label;
|
||||
i++;
|
||||
}
|
||||
rlfa_labels.nexthop_num = i;
|
||||
|
||||
lde_imsg_compose_parent(IMSG_RLFA_LABELS, 0, &rlfa_labels,
|
||||
sizeof(rlfa_labels));
|
||||
}
|
||||
|
||||
void lde_rlfa_label_update(const struct fec *fec)
|
||||
{
|
||||
struct ldp_rlfa_node *rnode;
|
||||
|
||||
if (fec->type != FEC_TYPE_IPV4
|
||||
|| fec->u.ipv4.prefixlen != IPV4_MAX_BITLEN)
|
||||
return;
|
||||
|
||||
/*
|
||||
* TODO: use an rb-tree lookup to restrict the iteration to the RLFAs
|
||||
* that were effectivelly affected by the label update.
|
||||
*/
|
||||
RB_FOREACH (rnode, ldp_rlfa_node_head, &rlfa_node_tree) {
|
||||
struct ldp_rlfa_client *rclient;
|
||||
|
||||
if (!IPV4_ADDR_SAME(&rnode->pq_address, &fec->u.ipv4.prefix))
|
||||
continue;
|
||||
|
||||
RB_FOREACH (rclient, ldp_rlfa_client_head, &rnode->clients)
|
||||
lde_rlfa_client_send(rclient);
|
||||
}
|
||||
}
|
||||
|
||||
void lde_rlfa_check(struct ldp_rlfa_client *rclient)
|
||||
{
|
||||
struct lde_nbr *ln;
|
||||
struct lde_map *me;
|
||||
struct fec fec;
|
||||
union ldpd_addr pq_address = {};
|
||||
|
||||
pq_address.v4 = rclient->node->pq_address;
|
||||
ln = lde_nbr_find_by_addr(AF_INET, &pq_address);
|
||||
if (!ln)
|
||||
return;
|
||||
|
||||
lde_prefix2fec(&rclient->node->destination, &fec);
|
||||
me = (struct lde_map *)fec_find(&ln->recv_map, &fec);
|
||||
if (!me)
|
||||
return;
|
||||
|
||||
rclient->node->pq_label = me->map.label;
|
||||
lde_rlfa_client_send(rclient);
|
||||
}
|
||||
|
||||
/*
|
||||
* Check if there's any registered RLFA client for this prefix/neighbor (PQ
|
||||
* node) and notify about the updated label.
|
||||
*/
|
||||
void lde_rlfa_update_clients(struct fec *fec, struct lde_nbr *ln,
|
||||
uint32_t label)
|
||||
{
|
||||
struct prefix rlfa_dest;
|
||||
struct ldp_rlfa_node *rnode;
|
||||
|
||||
lde_fec2prefix(fec, &rlfa_dest);
|
||||
rnode = rlfa_node_find(&rlfa_dest, ln->id);
|
||||
if (rnode) {
|
||||
struct ldp_rlfa_client *rclient;
|
||||
|
||||
rnode->pq_label = label;
|
||||
RB_FOREACH (rclient, ldp_rlfa_client_head, &rnode->clients)
|
||||
lde_rlfa_client_send(rclient);
|
||||
} else
|
||||
lde_rlfa_label_update(fec);
|
||||
}
|
||||
|
||||
void ldpe_rlfa_init(struct ldp_rlfa_client *rclient)
|
||||
{
|
||||
struct tnbr *tnbr;
|
||||
union ldpd_addr pq_address = {};
|
||||
|
||||
pq_address.v4 = rclient->node->pq_address;
|
||||
tnbr = tnbr_find(leconf, AF_INET, &pq_address);
|
||||
if (tnbr == NULL) {
|
||||
tnbr = tnbr_new(AF_INET, &pq_address);
|
||||
tnbr_update(tnbr);
|
||||
RB_INSERT(tnbr_head, &leconf->tnbr_tree, tnbr);
|
||||
}
|
||||
|
||||
tnbr->rlfa_count++;
|
||||
}
|
||||
|
||||
void ldpe_rlfa_exit(struct ldp_rlfa_client *rclient)
|
||||
{
|
||||
struct tnbr *tnbr;
|
||||
union ldpd_addr pq_address = {};
|
||||
|
||||
pq_address.v4 = rclient->node->pq_address;
|
||||
tnbr = tnbr_find(leconf, AF_INET, &pq_address);
|
||||
if (tnbr) {
|
||||
tnbr->rlfa_count--;
|
||||
tnbr_check(leconf, tnbr);
|
||||
}
|
||||
}
|
78
ldpd/rlfa.h
Normal file
78
ldpd/rlfa.h
Normal file
@ -0,0 +1,78 @@
|
||||
/*
|
||||
* Copyright (C) 2020 NetDEF, Inc.
|
||||
* Renato Westphal
|
||||
*
|
||||
* 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 _LDPD_RLFA_H_
|
||||
#define _LDPD_RLFA_H_
|
||||
|
||||
#include "openbsd-tree.h"
|
||||
#include "zclient.h"
|
||||
|
||||
struct ldp_rlfa_client {
|
||||
RB_ENTRY(ldp_rlfa_client) entry;
|
||||
|
||||
/* IGP instance data. */
|
||||
struct zapi_rlfa_igp igp;
|
||||
|
||||
/* Backpointer to RLFA node. */
|
||||
struct ldp_rlfa_node *node;
|
||||
};
|
||||
RB_HEAD(ldp_rlfa_client_head, ldp_rlfa_client);
|
||||
RB_PROTOTYPE(ldp_rlfa_client_head, ldp_rlfa_client, entry,
|
||||
ldp_rlfa_client_compare);
|
||||
|
||||
struct ldp_rlfa_node {
|
||||
RB_ENTRY(ldp_rlfa_node) entry;
|
||||
|
||||
/* Destination prefix. */
|
||||
struct prefix destination;
|
||||
|
||||
/* PQ node address. */
|
||||
struct in_addr pq_address;
|
||||
|
||||
/* RLFA clients. */
|
||||
struct ldp_rlfa_client_head clients;
|
||||
|
||||
/* Label allocated by the PQ node to the RLFA destination. */
|
||||
mpls_label_t pq_label;
|
||||
};
|
||||
RB_HEAD(ldp_rlfa_node_head, ldp_rlfa_node);
|
||||
RB_PROTOTYPE(ldp_rlfa_node_head, ldp_rlfa_node, entry, ldp_rlfa_node_compare);
|
||||
|
||||
extern struct ldp_rlfa_node_head rlfa_node_tree;
|
||||
|
||||
/* prototypes */
|
||||
struct ldp_rlfa_client *rlfa_client_new(struct ldp_rlfa_node *rnode,
|
||||
struct zapi_rlfa_igp *igp);
|
||||
void rlfa_client_del(struct ldp_rlfa_client *rclient);
|
||||
struct ldp_rlfa_client *rlfa_client_find(struct ldp_rlfa_node *rnode,
|
||||
struct zapi_rlfa_igp *igp);
|
||||
struct ldp_rlfa_node *rlfa_node_new(const struct prefix *destination,
|
||||
struct in_addr pq_address);
|
||||
void rlfa_node_del(struct ldp_rlfa_node *rnode);
|
||||
struct ldp_rlfa_node *rlfa_node_find(const struct prefix *destination,
|
||||
struct in_addr pq_address);
|
||||
void lde_rlfa_check(struct ldp_rlfa_client *rclient);
|
||||
void lde_rlfa_client_send(struct ldp_rlfa_client *rclient);
|
||||
void lde_rlfa_label_update(const struct fec *fec);
|
||||
void lde_rlfa_update_clients(struct fec *fec, struct lde_nbr *ln,
|
||||
uint32_t label);
|
||||
void ldpe_rlfa_init(struct ldp_rlfa_client *rclient);
|
||||
void ldpe_rlfa_exit(struct ldp_rlfa_client *rclient);
|
||||
|
||||
#endif /* _LDPD_RLFA_H_ */
|
@ -36,6 +36,7 @@ ldpd_libldp_a_SOURCES = \
|
||||
ldpd/notification.c \
|
||||
ldpd/packet.c \
|
||||
ldpd/pfkey.c \
|
||||
ldpd/rlfa.c \
|
||||
ldpd/socket.c \
|
||||
ldpd/util.c \
|
||||
# end
|
||||
@ -53,6 +54,7 @@ noinst_HEADERS += \
|
||||
ldpd/ldpd.h \
|
||||
ldpd/ldpe.h \
|
||||
ldpd/log.h \
|
||||
ldpd/rlfa.h \
|
||||
# end
|
||||
|
||||
ldpd_ldpd_SOURCES = ldpd/ldpd.c
|
||||
|
@ -634,6 +634,52 @@ struct zapi_pw_status {
|
||||
uint32_t status;
|
||||
};
|
||||
|
||||
/* IGP instance data associated to a RLFA. */
|
||||
struct zapi_rlfa_igp {
|
||||
vrf_id_t vrf_id;
|
||||
int protocol;
|
||||
union {
|
||||
struct {
|
||||
char area_tag[32];
|
||||
struct {
|
||||
int tree_id;
|
||||
int level;
|
||||
unsigned int run_id;
|
||||
} spf;
|
||||
} isis;
|
||||
};
|
||||
};
|
||||
|
||||
/* IGP -> LDP RLFA (un)registration message. */
|
||||
struct zapi_rlfa_request {
|
||||
/* IGP instance data. */
|
||||
struct zapi_rlfa_igp igp;
|
||||
|
||||
/* Destination prefix. */
|
||||
struct prefix destination;
|
||||
|
||||
/* PQ node address. */
|
||||
struct in_addr pq_address;
|
||||
};
|
||||
|
||||
/* LDP -> IGP RLFA label update. */
|
||||
struct zapi_rlfa_response {
|
||||
/* IGP instance data. */
|
||||
struct zapi_rlfa_igp igp;
|
||||
|
||||
/* Destination prefix. */
|
||||
struct prefix destination;
|
||||
|
||||
/* Resolved LDP labels. */
|
||||
mpls_label_t pq_label;
|
||||
uint16_t nexthop_num;
|
||||
struct {
|
||||
int family;
|
||||
union g_addr gate;
|
||||
mpls_label_t label;
|
||||
} nexthops[MULTIPATH_NUM];
|
||||
};
|
||||
|
||||
enum zapi_route_notify_owner {
|
||||
ZAPI_ROUTE_FAIL_INSTALL,
|
||||
ZAPI_ROUTE_BETTER_ADMIN_WON,
|
||||
@ -1091,6 +1137,12 @@ enum zapi_opaque_registry {
|
||||
LDP_IGP_SYNC_IF_STATE_UPDATE = 4,
|
||||
/* Announce that LDP is up */
|
||||
LDP_IGP_SYNC_ANNOUNCE_UPDATE = 5,
|
||||
/* Register RLFA with LDP */
|
||||
LDP_RLFA_REGISTER = 7,
|
||||
/* Unregister all RLFAs with LDP */
|
||||
LDP_RLFA_UNREGISTER_ALL = 8,
|
||||
/* Announce LDP labels associated to a previously registered RLFA */
|
||||
LDP_RLFA_LABELS = 9,
|
||||
};
|
||||
|
||||
/* Send the hello message.
|
||||
|
@ -69,6 +69,24 @@ test_find_adjacency(const struct isis_test_node *tnode, const char *hostname)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
mpls_label_t test_topology_node_ldp_label(const struct isis_topology *topology,
|
||||
struct in_addr router_id)
|
||||
{
|
||||
for (size_t i = 0; topology->nodes[i].hostname[0]; i++) {
|
||||
const struct isis_test_node *tnode = &topology->nodes[i];
|
||||
struct in_addr node_router_id;
|
||||
|
||||
if (!tnode->router_id)
|
||||
continue;
|
||||
|
||||
(void)inet_pton(AF_INET, tnode->router_id, &node_router_id);
|
||||
if (IPV4_ADDR_SAME(&router_id, &node_router_id))
|
||||
return (50000 + (i + 1) * 100);
|
||||
}
|
||||
|
||||
return MPLS_INVALID_LABEL;
|
||||
}
|
||||
|
||||
static struct isis_lsp *lsp_add(struct lspdb_head *lspdb,
|
||||
struct isis_area *area, int level,
|
||||
const uint8_t *sysid, uint8_t pseudonode_id)
|
||||
|
@ -70,6 +70,9 @@ test_topology_find_node(const struct isis_topology *topology,
|
||||
const char *hostname, uint8_t pseudonode_id);
|
||||
extern const struct isis_topology *
|
||||
test_topology_find(struct isis_topology *test_topologies, uint16_t number);
|
||||
extern mpls_label_t
|
||||
test_topology_node_ldp_label(const struct isis_topology *topology,
|
||||
struct in_addr router_id);
|
||||
extern int test_topology_load(const struct isis_topology *topology,
|
||||
struct isis_area *area,
|
||||
struct lspdb_head lspdb[]);
|
||||
|
@ -31,6 +31,7 @@
|
||||
#include "isisd/isisd.h"
|
||||
#include "isisd/isis_dynhn.h"
|
||||
#include "isisd/isis_misc.h"
|
||||
#include "isisd/isis_route.h"
|
||||
#include "isisd/isis_spf.h"
|
||||
#include "isisd/isis_spf_private.h"
|
||||
|
||||
@ -40,6 +41,7 @@ enum test_type {
|
||||
TEST_SPF = 1,
|
||||
TEST_REVERSE_SPF,
|
||||
TEST_LFA,
|
||||
TEST_RLFA,
|
||||
TEST_TI_LFA,
|
||||
};
|
||||
|
||||
@ -105,6 +107,86 @@ static void test_run_lfa(struct vty *vty, const struct isis_topology *topology,
|
||||
isis_spftree_del(spftree_self);
|
||||
}
|
||||
|
||||
static void test_run_rlfa(struct vty *vty, const struct isis_topology *topology,
|
||||
const struct isis_test_node *root,
|
||||
struct isis_area *area, struct lspdb_head *lspdb,
|
||||
int level, int tree,
|
||||
struct lfa_protected_resource *protected_resource)
|
||||
{
|
||||
struct isis_spftree *spftree_self;
|
||||
struct isis_spftree *spftree_reverse;
|
||||
struct isis_spftree *spftree_pc;
|
||||
struct isis_spf_node *spf_node, *node;
|
||||
struct rlfa *rlfa;
|
||||
uint8_t flags;
|
||||
|
||||
/* Run forward SPF in the root node. */
|
||||
flags = F_SPFTREE_NO_ADJACENCIES;
|
||||
spftree_self = isis_spftree_new(area, lspdb, root->sysid, level, tree,
|
||||
SPF_TYPE_FORWARD, flags);
|
||||
isis_run_spf(spftree_self);
|
||||
|
||||
/* Run reverse SPF in the root node. */
|
||||
spftree_reverse = isis_spf_reverse_run(spftree_self);
|
||||
|
||||
/* Run forward SPF on all adjacent routers. */
|
||||
isis_spf_run_neighbors(spftree_self);
|
||||
|
||||
/* Compute the local LFA repair paths. */
|
||||
isis_lfa_compute(area, NULL, spftree_self, protected_resource);
|
||||
|
||||
/* Compute the remote LFA repair paths. */
|
||||
spftree_pc = isis_rlfa_compute(area, spftree_self, spftree_reverse, 0,
|
||||
protected_resource);
|
||||
|
||||
/* Print the extended P-space and Q-space. */
|
||||
vty_out(vty, "P-space (self):\n");
|
||||
RB_FOREACH (node, isis_spf_nodes, &spftree_pc->lfa.p_space)
|
||||
vty_out(vty, " %s\n", print_sys_hostname(node->sysid));
|
||||
vty_out(vty, "\n");
|
||||
RB_FOREACH (spf_node, isis_spf_nodes, &spftree_self->adj_nodes) {
|
||||
if (RB_EMPTY(isis_spf_nodes, &spf_node->lfa.p_space))
|
||||
continue;
|
||||
vty_out(vty, "P-space (%s):\n",
|
||||
print_sys_hostname(spf_node->sysid));
|
||||
RB_FOREACH (node, isis_spf_nodes, &spf_node->lfa.p_space)
|
||||
vty_out(vty, " %s\n", print_sys_hostname(node->sysid));
|
||||
vty_out(vty, "\n");
|
||||
}
|
||||
vty_out(vty, "Q-space:\n");
|
||||
RB_FOREACH (node, isis_spf_nodes, &spftree_pc->lfa.q_space)
|
||||
vty_out(vty, " %s\n", print_sys_hostname(node->sysid));
|
||||
vty_out(vty, "\n");
|
||||
|
||||
/* Print the post-convergence SPT. */
|
||||
isis_print_spftree(vty, spftree_pc);
|
||||
|
||||
/*
|
||||
* Activate the computed RLFAs (if any) using artificial LDP labels for
|
||||
* the PQ nodes.
|
||||
*/
|
||||
frr_each_safe (rlfa_tree, &spftree_self->lfa.remote.rlfas, rlfa) {
|
||||
struct zapi_rlfa_response response = {};
|
||||
|
||||
response.pq_label = test_topology_node_ldp_label(
|
||||
topology, rlfa->pq_address);
|
||||
assert(response.pq_label != MPLS_INVALID_LABEL);
|
||||
isis_rlfa_activate(spftree_self, rlfa, &response);
|
||||
}
|
||||
|
||||
/* Print the SPT and the corresponding main/backup routing tables. */
|
||||
isis_print_spftree(vty, spftree_self);
|
||||
vty_out(vty, "Main:\n");
|
||||
isis_print_routes(vty, spftree_self, false, false);
|
||||
vty_out(vty, "Backup:\n");
|
||||
isis_print_routes(vty, spftree_self, false, true);
|
||||
|
||||
/* Cleanup everything. */
|
||||
isis_spftree_del(spftree_self);
|
||||
isis_spftree_del(spftree_reverse);
|
||||
isis_spftree_del(spftree_pc);
|
||||
}
|
||||
|
||||
static void test_run_ti_lfa(struct vty *vty,
|
||||
const struct isis_topology *topology,
|
||||
const struct isis_test_node *root,
|
||||
@ -242,6 +324,11 @@ static int test_run(struct vty *vty, const struct isis_topology *topology,
|
||||
&area->lspdb[level - 1], level,
|
||||
tree, &protected_resource);
|
||||
break;
|
||||
case TEST_RLFA:
|
||||
test_run_rlfa(vty, topology, root, area,
|
||||
&area->lspdb[level - 1], level,
|
||||
tree, &protected_resource);
|
||||
break;
|
||||
case TEST_TI_LFA:
|
||||
test_run_ti_lfa(vty, topology, root, area,
|
||||
&area->lspdb[level - 1], level,
|
||||
@ -266,6 +353,7 @@ DEFUN(test_isis, test_isis_cmd,
|
||||
spf\
|
||||
|reverse-spf\
|
||||
|lfa system-id WORD [pseudonode-id <1-255>]\
|
||||
|remote-lfa system-id WORD [pseudonode-id <1-255>]\
|
||||
|ti-lfa system-id WORD [pseudonode-id <1-255>] [node-protection]\
|
||||
>\
|
||||
[display-lspdb] [<ipv4-only|ipv6-only>] [<level-1-only|level-2-only>]",
|
||||
@ -282,6 +370,11 @@ DEFUN(test_isis, test_isis_cmd,
|
||||
"System ID\n"
|
||||
"Pseudonode-ID\n"
|
||||
"Pseudonode-ID\n"
|
||||
"Remote LFA\n"
|
||||
"System ID\n"
|
||||
"System ID\n"
|
||||
"Pseudonode-ID\n"
|
||||
"Pseudonode-ID\n"
|
||||
"Topology Independent LFA\n"
|
||||
"System ID\n"
|
||||
"System ID\n"
|
||||
@ -330,6 +423,14 @@ DEFUN(test_isis, test_isis_cmd,
|
||||
else if (argv_find(argv, argc, "lfa", &idx)) {
|
||||
test_type = TEST_LFA;
|
||||
|
||||
fail_sysid_str = argv[idx + 2]->arg;
|
||||
if (argv_find(argv, argc, "pseudonode-id", &idx))
|
||||
fail_pseudonode_id =
|
||||
strtoul(argv[idx + 1]->arg, NULL, 10);
|
||||
protection_type = LFA_LINK_PROTECTION;
|
||||
} else if (argv_find(argv, argc, "remote-lfa", &idx)) {
|
||||
test_type = TEST_RLFA;
|
||||
|
||||
fail_sysid_str = argv[idx + 2]->arg;
|
||||
if (argv_find(argv, argc, "pseudonode-id", &idx))
|
||||
fail_pseudonode_id =
|
||||
|
@ -31,6 +31,18 @@ test isis topology 14 root rt1 lfa system-id rt1 pseudonode-id 1
|
||||
test isis topology 14 root rt1 lfa system-id rt2
|
||||
test isis topology 14 root rt5 lfa system-id rt4
|
||||
|
||||
test isis topology 1 root rt1 remote-lfa system-id rt2
|
||||
test isis topology 2 root rt5 remote-lfa system-id rt1 pseudonode-id 1
|
||||
test isis topology 3 root rt5 remote-lfa system-id rt4 ipv4-only
|
||||
test isis topology 3 root rt5 remote-lfa system-id rt3 ipv4-only
|
||||
test isis topology 5 root rt1 remote-lfa system-id rt2 ipv4-only
|
||||
test isis topology 6 root rt4 remote-lfa system-id rt3 ipv4-only
|
||||
test isis topology 7 root rt11 remote-lfa system-id rt8 ipv4-only
|
||||
test isis topology 7 root rt6 remote-lfa system-id rt5 ipv4-only
|
||||
test isis topology 8 root rt2 remote-lfa system-id rt5 ipv4-only
|
||||
test isis topology 11 root rt2 remote-lfa system-id rt4
|
||||
test isis topology 13 root rt1 remote-lfa system-id rt3 ipv4-only
|
||||
|
||||
test isis topology 1 root rt1 ti-lfa system-id rt2
|
||||
test isis topology 2 root rt1 ti-lfa system-id rt3
|
||||
test isis topology 2 root rt1 ti-lfa system-id rt1 pseudonode-id 1
|
||||
|
File diff suppressed because it is too large
Load Diff
0
tests/topotests/isis-rlfa-topo1/__init__.py
Normal file
0
tests/topotests/isis-rlfa-topo1/__init__.py
Normal file
39
tests/topotests/isis-rlfa-topo1/rt1/isisd.conf
Normal file
39
tests/topotests/isis-rlfa-topo1/rt1/isisd.conf
Normal file
@ -0,0 +1,39 @@
|
||||
password 1
|
||||
hostname rt1
|
||||
log file isisd.log
|
||||
!
|
||||
debug isis events
|
||||
debug isis route-events
|
||||
debug isis spf-events
|
||||
debug isis lsp-gen
|
||||
!
|
||||
interface lo
|
||||
ip router isis 1
|
||||
ipv6 router isis 1
|
||||
isis passive
|
||||
!
|
||||
interface eth-rt2
|
||||
ip router isis 1
|
||||
ipv6 router isis 1
|
||||
isis hello-multiplier 3
|
||||
isis network point-to-point
|
||||
isis fast-reroute lfa
|
||||
isis fast-reroute remote-lfa tunnel mpls-ldp
|
||||
!
|
||||
interface eth-rt3
|
||||
ip router isis 1
|
||||
ipv6 router isis 1
|
||||
isis hello-multiplier 3
|
||||
isis network point-to-point
|
||||
isis fast-reroute lfa
|
||||
isis fast-reroute remote-lfa tunnel mpls-ldp
|
||||
!
|
||||
ip prefix-list PLIST seq 5 permit 10.0.255.8/32
|
||||
!
|
||||
router isis 1
|
||||
net 49.0000.0000.0000.0001.00
|
||||
is-type level-1-2
|
||||
lsp-gen-interval 2
|
||||
topology ipv6-unicast
|
||||
fast-reroute remote-lfa prefix-list PLIST
|
||||
!
|
30
tests/topotests/isis-rlfa-topo1/rt1/ldpd.conf
Normal file
30
tests/topotests/isis-rlfa-topo1/rt1/ldpd.conf
Normal file
@ -0,0 +1,30 @@
|
||||
log file ldpd.log
|
||||
!
|
||||
hostname rt1
|
||||
!
|
||||
debug mpls ldp messages recv
|
||||
debug mpls ldp messages sent
|
||||
debug mpls ldp zebra
|
||||
!
|
||||
mpls ldp
|
||||
router-id 10.0.255.1
|
||||
dual-stack transport-connection prefer ipv4
|
||||
!
|
||||
address-family ipv4
|
||||
label local allocate host-routes
|
||||
discovery targeted-hello accept
|
||||
discovery transport-address 10.0.255.1
|
||||
!
|
||||
interface eth-rt2
|
||||
interface eth-rt3
|
||||
!
|
||||
!
|
||||
address-family ipv6
|
||||
label local allocate host-routes
|
||||
discovery transport-address 2001:db8::1
|
||||
!
|
||||
interface eth-rt2
|
||||
interface eth-rt3
|
||||
!
|
||||
!
|
||||
!
|
235
tests/topotests/isis-rlfa-topo1/rt1/step1/show_ip_route.ref
Normal file
235
tests/topotests/isis-rlfa-topo1/rt1/step1/show_ip_route.ref
Normal file
@ -0,0 +1,235 @@
|
||||
{
|
||||
"10.0.255.2\/32":[
|
||||
{
|
||||
"prefix":"10.0.255.2\/32",
|
||||
"protocol":"isis",
|
||||
"selected":true,
|
||||
"destSelected":true,
|
||||
"distance":115,
|
||||
"metric":20,
|
||||
"installed":true,
|
||||
"nexthops":[
|
||||
{
|
||||
"fib":true,
|
||||
"ip":"10.0.255.2",
|
||||
"afi":"ipv4",
|
||||
"interfaceName":"eth-rt2",
|
||||
"active":true,
|
||||
"onLink":true,
|
||||
"backupIndex":[
|
||||
0
|
||||
]
|
||||
}
|
||||
],
|
||||
"backupNexthops":[
|
||||
{
|
||||
"ip":"10.0.255.3",
|
||||
"afi":"ipv4",
|
||||
"interfaceName":"eth-rt3",
|
||||
"active":true,
|
||||
"onLink":true,
|
||||
"labels":"*"
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"10.0.255.3\/32":[
|
||||
{
|
||||
"prefix":"10.0.255.3\/32",
|
||||
"protocol":"isis",
|
||||
"selected":true,
|
||||
"destSelected":true,
|
||||
"distance":115,
|
||||
"metric":20,
|
||||
"installed":true,
|
||||
"nexthops":[
|
||||
{
|
||||
"fib":true,
|
||||
"ip":"10.0.255.3",
|
||||
"afi":"ipv4",
|
||||
"interfaceName":"eth-rt3",
|
||||
"active":true,
|
||||
"onLink":true,
|
||||
"backupIndex":[
|
||||
0
|
||||
]
|
||||
}
|
||||
],
|
||||
"backupNexthops":[
|
||||
{
|
||||
"ip":"10.0.255.2",
|
||||
"afi":"ipv4",
|
||||
"interfaceName":"eth-rt2",
|
||||
"active":true,
|
||||
"onLink":true,
|
||||
"labels":"*"
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"10.0.255.4\/32":[
|
||||
{
|
||||
"prefix":"10.0.255.4\/32",
|
||||
"protocol":"isis",
|
||||
"selected":true,
|
||||
"destSelected":true,
|
||||
"distance":115,
|
||||
"metric":30,
|
||||
"installed":true,
|
||||
"nexthops":[
|
||||
{
|
||||
"fib":true,
|
||||
"ip":"10.0.255.2",
|
||||
"afi":"ipv4",
|
||||
"interfaceName":"eth-rt2",
|
||||
"active":true,
|
||||
"onLink":true,
|
||||
"backupIndex":[
|
||||
0
|
||||
]
|
||||
}
|
||||
],
|
||||
"backupNexthops":[
|
||||
{
|
||||
"ip":"10.0.255.3",
|
||||
"afi":"ipv4",
|
||||
"interfaceName":"eth-rt3",
|
||||
"active":true,
|
||||
"onLink":true,
|
||||
"labels":"*"
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"10.0.255.5\/32":[
|
||||
{
|
||||
"prefix":"10.0.255.5\/32",
|
||||
"protocol":"isis",
|
||||
"selected":true,
|
||||
"destSelected":true,
|
||||
"distance":115,
|
||||
"metric":30,
|
||||
"installed":true,
|
||||
"nexthops":[
|
||||
{
|
||||
"fib":true,
|
||||
"ip":"10.0.255.3",
|
||||
"afi":"ipv4",
|
||||
"interfaceName":"eth-rt3",
|
||||
"active":true,
|
||||
"onLink":true,
|
||||
"backupIndex":[
|
||||
0
|
||||
]
|
||||
}
|
||||
],
|
||||
"backupNexthops":[
|
||||
{
|
||||
"ip":"10.0.255.2",
|
||||
"afi":"ipv4",
|
||||
"interfaceName":"eth-rt2",
|
||||
"active":true,
|
||||
"onLink":true,
|
||||
"labels":"*"
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"10.0.255.6\/32":[
|
||||
{
|
||||
"prefix":"10.0.255.6\/32",
|
||||
"protocol":"isis",
|
||||
"selected":true,
|
||||
"destSelected":true,
|
||||
"distance":115,
|
||||
"metric":40,
|
||||
"installed":true,
|
||||
"nexthops":[
|
||||
{
|
||||
"fib":true,
|
||||
"ip":"10.0.255.2",
|
||||
"afi":"ipv4",
|
||||
"interfaceName":"eth-rt2",
|
||||
"active":true,
|
||||
"onLink":true,
|
||||
"backupIndex":[
|
||||
0
|
||||
]
|
||||
}
|
||||
],
|
||||
"backupNexthops":[
|
||||
{
|
||||
"ip":"10.0.255.3",
|
||||
"afi":"ipv4",
|
||||
"interfaceName":"eth-rt3",
|
||||
"active":true,
|
||||
"onLink":true,
|
||||
"labels":"*"
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"10.0.255.7\/32":[
|
||||
{
|
||||
"prefix":"10.0.255.7\/32",
|
||||
"protocol":"isis",
|
||||
"selected":true,
|
||||
"destSelected":true,
|
||||
"distance":115,
|
||||
"metric":40,
|
||||
"installed":true,
|
||||
"nexthops":[
|
||||
{
|
||||
"fib":true,
|
||||
"ip":"10.0.255.3",
|
||||
"afi":"ipv4",
|
||||
"interfaceName":"eth-rt3",
|
||||
"active":true,
|
||||
"onLink":true,
|
||||
"backupIndex":[
|
||||
0
|
||||
]
|
||||
}
|
||||
],
|
||||
"backupNexthops":[
|
||||
{
|
||||
"ip":"10.0.255.2",
|
||||
"afi":"ipv4",
|
||||
"interfaceName":"eth-rt2",
|
||||
"active":true,
|
||||
"onLink":true,
|
||||
"labels":"*"
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"10.0.255.8\/32":[
|
||||
{
|
||||
"prefix":"10.0.255.8\/32",
|
||||
"protocol":"isis",
|
||||
"selected":true,
|
||||
"destSelected":true,
|
||||
"distance":115,
|
||||
"metric":50,
|
||||
"installed":true,
|
||||
"nexthops":[
|
||||
{
|
||||
"fib":true,
|
||||
"ip":"10.0.255.2",
|
||||
"afi":"ipv4",
|
||||
"interfaceName":"eth-rt2",
|
||||
"active":true,
|
||||
"onLink":true
|
||||
},
|
||||
{
|
||||
"fib":true,
|
||||
"ip":"10.0.255.3",
|
||||
"afi":"ipv4",
|
||||
"interfaceName":"eth-rt3",
|
||||
"active":true,
|
||||
"onLink":true
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
207
tests/topotests/isis-rlfa-topo1/rt1/step1/show_ipv6_route.ref
Normal file
207
tests/topotests/isis-rlfa-topo1/rt1/step1/show_ipv6_route.ref
Normal file
@ -0,0 +1,207 @@
|
||||
{
|
||||
"2001:db8::2\/128":[
|
||||
{
|
||||
"prefix":"2001:db8::2\/128",
|
||||
"protocol":"isis",
|
||||
"selected":true,
|
||||
"destSelected":true,
|
||||
"distance":115,
|
||||
"metric":20,
|
||||
"installed":true,
|
||||
"nexthops":[
|
||||
{
|
||||
"fib":true,
|
||||
"afi":"ipv6",
|
||||
"interfaceName":"eth-rt2",
|
||||
"active":true,
|
||||
"backupIndex":[
|
||||
0
|
||||
]
|
||||
}
|
||||
],
|
||||
"backupNexthops":[
|
||||
{
|
||||
"afi":"ipv6",
|
||||
"interfaceName":"eth-rt3",
|
||||
"active":true,
|
||||
"labels":"*"
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"2001:db8::3\/128":[
|
||||
{
|
||||
"prefix":"2001:db8::3\/128",
|
||||
"protocol":"isis",
|
||||
"selected":true,
|
||||
"destSelected":true,
|
||||
"distance":115,
|
||||
"metric":20,
|
||||
"installed":true,
|
||||
"nexthops":[
|
||||
{
|
||||
"fib":true,
|
||||
"afi":"ipv6",
|
||||
"interfaceName":"eth-rt3",
|
||||
"active":true,
|
||||
"backupIndex":[
|
||||
0
|
||||
]
|
||||
}
|
||||
],
|
||||
"backupNexthops":[
|
||||
{
|
||||
"afi":"ipv6",
|
||||
"interfaceName":"eth-rt2",
|
||||
"active":true,
|
||||
"labels":"*"
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"2001:db8::4\/128":[
|
||||
{
|
||||
"prefix":"2001:db8::4\/128",
|
||||
"protocol":"isis",
|
||||
"selected":true,
|
||||
"destSelected":true,
|
||||
"distance":115,
|
||||
"metric":30,
|
||||
"installed":true,
|
||||
"nexthops":[
|
||||
{
|
||||
"fib":true,
|
||||
"afi":"ipv6",
|
||||
"interfaceName":"eth-rt2",
|
||||
"active":true,
|
||||
"backupIndex":[
|
||||
0
|
||||
]
|
||||
}
|
||||
],
|
||||
"backupNexthops":[
|
||||
{
|
||||
"afi":"ipv6",
|
||||
"interfaceName":"eth-rt3",
|
||||
"active":true,
|
||||
"labels":"*"
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"2001:db8::5\/128":[
|
||||
{
|
||||
"prefix":"2001:db8::5\/128",
|
||||
"protocol":"isis",
|
||||
"selected":true,
|
||||
"destSelected":true,
|
||||
"distance":115,
|
||||
"metric":30,
|
||||
"installed":true,
|
||||
"nexthops":[
|
||||
{
|
||||
"fib":true,
|
||||
"afi":"ipv6",
|
||||
"interfaceName":"eth-rt3",
|
||||
"active":true,
|
||||
"backupIndex":[
|
||||
0
|
||||
]
|
||||
}
|
||||
],
|
||||
"backupNexthops":[
|
||||
{
|
||||
"afi":"ipv6",
|
||||
"interfaceName":"eth-rt2",
|
||||
"active":true,
|
||||
"labels":"*"
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"2001:db8::6\/128":[
|
||||
{
|
||||
"prefix":"2001:db8::6\/128",
|
||||
"protocol":"isis",
|
||||
"selected":true,
|
||||
"destSelected":true,
|
||||
"distance":115,
|
||||
"metric":40,
|
||||
"installed":true,
|
||||
"nexthops":[
|
||||
{
|
||||
"fib":true,
|
||||
"afi":"ipv6",
|
||||
"interfaceName":"eth-rt2",
|
||||
"active":true,
|
||||
"backupIndex":[
|
||||
0
|
||||
]
|
||||
}
|
||||
],
|
||||
"backupNexthops":[
|
||||
{
|
||||
"afi":"ipv6",
|
||||
"interfaceName":"eth-rt3",
|
||||
"active":true,
|
||||
"labels":"*"
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"2001:db8::7\/128":[
|
||||
{
|
||||
"prefix":"2001:db8::7\/128",
|
||||
"protocol":"isis",
|
||||
"selected":true,
|
||||
"destSelected":true,
|
||||
"distance":115,
|
||||
"metric":40,
|
||||
"installed":true,
|
||||
"nexthops":[
|
||||
{
|
||||
"fib":true,
|
||||
"afi":"ipv6",
|
||||
"interfaceName":"eth-rt3",
|
||||
"active":true,
|
||||
"backupIndex":[
|
||||
0
|
||||
]
|
||||
}
|
||||
],
|
||||
"backupNexthops":[
|
||||
{
|
||||
"afi":"ipv6",
|
||||
"interfaceName":"eth-rt2",
|
||||
"active":true,
|
||||
"labels":"*"
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"2001:db8::8\/128":[
|
||||
{
|
||||
"prefix":"2001:db8::8\/128",
|
||||
"protocol":"isis",
|
||||
"selected":true,
|
||||
"destSelected":true,
|
||||
"distance":115,
|
||||
"metric":50,
|
||||
"installed":true,
|
||||
"nexthops":[
|
||||
{
|
||||
"fib":true,
|
||||
"afi":"ipv6",
|
||||
"interfaceName":"eth-rt3",
|
||||
"active":true
|
||||
},
|
||||
{
|
||||
"fib":true,
|
||||
"afi":"ipv6",
|
||||
"interfaceName":"eth-rt2",
|
||||
"active":true
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
@ -0,0 +1,44 @@
|
||||
{
|
||||
"frr-interface:lib": {
|
||||
"interface": [
|
||||
{
|
||||
"name": "eth-rt2",
|
||||
"vrf": "default",
|
||||
"state": {
|
||||
"frr-isisd:isis": {
|
||||
"adjacencies": {
|
||||
"adjacency": [
|
||||
{
|
||||
"neighbor-sys-type": "level-1-2",
|
||||
"neighbor-sysid": "0000.0000.0002",
|
||||
"hold-timer": 9,
|
||||
"neighbor-priority": 0,
|
||||
"state": "up"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "eth-rt3",
|
||||
"vrf": "default",
|
||||
"state": {
|
||||
"frr-isisd:isis": {
|
||||
"adjacencies": {
|
||||
"adjacency": [
|
||||
{
|
||||
"neighbor-sys-type": "level-1-2",
|
||||
"neighbor-sysid": "0000.0000.0003",
|
||||
"hold-timer": 9,
|
||||
"neighbor-priority": 0,
|
||||
"state": "up"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
@ -0,0 +1,68 @@
|
||||
--- a/rt1/step9/show_ip_route.ref
|
||||
+++ b/rt1/step10/show_ip_route.ref
|
||||
@@ -15,7 +15,20 @@
|
||||
"afi":"ipv4",
|
||||
"interfaceName":"eth-rt2",
|
||||
"active":true,
|
||||
- "onLink":true
|
||||
+ "onLink":true,
|
||||
+ "backupIndex":[
|
||||
+ 0
|
||||
+ ]
|
||||
+ }
|
||||
+ ],
|
||||
+ "backupNexthops":[
|
||||
+ {
|
||||
+ "ip":"10.0.255.3",
|
||||
+ "afi":"ipv4",
|
||||
+ "interfaceName":"eth-rt3",
|
||||
+ "active":true,
|
||||
+ "onLink":true,
|
||||
+ "labels":"*"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -70,7 +83,20 @@
|
||||
"afi":"ipv4",
|
||||
"interfaceName":"eth-rt2",
|
||||
"active":true,
|
||||
- "onLink":true
|
||||
+ "onLink":true,
|
||||
+ "backupIndex":[
|
||||
+ 0
|
||||
+ ]
|
||||
+ }
|
||||
+ ],
|
||||
+ "backupNexthops":[
|
||||
+ {
|
||||
+ "ip":"10.0.255.3",
|
||||
+ "afi":"ipv4",
|
||||
+ "interfaceName":"eth-rt3",
|
||||
+ "active":true,
|
||||
+ "onLink":true,
|
||||
+ "labels":"*"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -125,7 +151,20 @@
|
||||
"afi":"ipv4",
|
||||
"interfaceName":"eth-rt2",
|
||||
"active":true,
|
||||
- "onLink":true
|
||||
+ "onLink":true,
|
||||
+ "backupIndex":[
|
||||
+ 0
|
||||
+ ]
|
||||
+ }
|
||||
+ ],
|
||||
+ "backupNexthops":[
|
||||
+ {
|
||||
+ "ip":"10.0.255.3",
|
||||
+ "afi":"ipv4",
|
||||
+ "interfaceName":"eth-rt3",
|
||||
+ "active":true,
|
||||
+ "onLink":true,
|
||||
+ "labels":"*"
|
||||
}
|
||||
]
|
||||
}
|
@ -0,0 +1,62 @@
|
||||
--- a/rt1/step9/show_ipv6_route.ref
|
||||
+++ b/rt1/step10/show_ipv6_route.ref
|
||||
@@ -13,7 +13,18 @@
|
||||
"fib":true,
|
||||
"afi":"ipv6",
|
||||
"interfaceName":"eth-rt2",
|
||||
- "active":true
|
||||
+ "active":true,
|
||||
+ "backupIndex":[
|
||||
+ 0
|
||||
+ ]
|
||||
+ }
|
||||
+ ],
|
||||
+ "backupNexthops":[
|
||||
+ {
|
||||
+ "afi":"ipv6",
|
||||
+ "interfaceName":"eth-rt3",
|
||||
+ "active":true,
|
||||
+ "labels":"*"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -62,7 +73,18 @@
|
||||
"fib":true,
|
||||
"afi":"ipv6",
|
||||
"interfaceName":"eth-rt2",
|
||||
- "active":true
|
||||
+ "active":true,
|
||||
+ "backupIndex":[
|
||||
+ 0
|
||||
+ ]
|
||||
+ }
|
||||
+ ],
|
||||
+ "backupNexthops":[
|
||||
+ {
|
||||
+ "afi":"ipv6",
|
||||
+ "interfaceName":"eth-rt3",
|
||||
+ "active":true,
|
||||
+ "labels":"*"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -111,7 +133,18 @@
|
||||
"fib":true,
|
||||
"afi":"ipv6",
|
||||
"interfaceName":"eth-rt2",
|
||||
- "active":true
|
||||
+ "active":true,
|
||||
+ "backupIndex":[
|
||||
+ 0
|
||||
+ ]
|
||||
+ }
|
||||
+ ],
|
||||
+ "backupNexthops":[
|
||||
+ {
|
||||
+ "afi":"ipv6",
|
||||
+ "interfaceName":"eth-rt3",
|
||||
+ "active":true,
|
||||
+ "labels":"*"
|
||||
}
|
||||
]
|
||||
}
|
134
tests/topotests/isis-rlfa-topo1/rt1/step2/show_ip_route.ref.diff
Normal file
134
tests/topotests/isis-rlfa-topo1/rt1/step2/show_ip_route.ref.diff
Normal file
@ -0,0 +1,134 @@
|
||||
--- a/rt1/step1/show_ip_route.ref
|
||||
+++ b/rt1/step2/show_ip_route.ref
|
||||
@@ -15,20 +15,7 @@
|
||||
"afi":"ipv4",
|
||||
"interfaceName":"eth-rt2",
|
||||
"active":true,
|
||||
- "onLink":true,
|
||||
- "backupIndex":[
|
||||
- 0
|
||||
- ]
|
||||
- }
|
||||
- ],
|
||||
- "backupNexthops":[
|
||||
- {
|
||||
- "ip":"10.0.255.3",
|
||||
- "afi":"ipv4",
|
||||
- "interfaceName":"eth-rt3",
|
||||
- "active":true,
|
||||
- "onLink":true,
|
||||
- "labels":"*"
|
||||
+ "onLink":true
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -49,20 +36,7 @@
|
||||
"afi":"ipv4",
|
||||
"interfaceName":"eth-rt3",
|
||||
"active":true,
|
||||
- "onLink":true,
|
||||
- "backupIndex":[
|
||||
- 0
|
||||
- ]
|
||||
- }
|
||||
- ],
|
||||
- "backupNexthops":[
|
||||
- {
|
||||
- "ip":"10.0.255.2",
|
||||
- "afi":"ipv4",
|
||||
- "interfaceName":"eth-rt2",
|
||||
- "active":true,
|
||||
- "onLink":true,
|
||||
- "labels":"*"
|
||||
+ "onLink":true
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -83,20 +57,7 @@
|
||||
"afi":"ipv4",
|
||||
"interfaceName":"eth-rt2",
|
||||
"active":true,
|
||||
- "onLink":true,
|
||||
- "backupIndex":[
|
||||
- 0
|
||||
- ]
|
||||
- }
|
||||
- ],
|
||||
- "backupNexthops":[
|
||||
- {
|
||||
- "ip":"10.0.255.3",
|
||||
- "afi":"ipv4",
|
||||
- "interfaceName":"eth-rt3",
|
||||
- "active":true,
|
||||
- "onLink":true,
|
||||
- "labels":"*"
|
||||
+ "onLink":true
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -117,20 +78,7 @@
|
||||
"afi":"ipv4",
|
||||
"interfaceName":"eth-rt3",
|
||||
"active":true,
|
||||
- "onLink":true,
|
||||
- "backupIndex":[
|
||||
- 0
|
||||
- ]
|
||||
- }
|
||||
- ],
|
||||
- "backupNexthops":[
|
||||
- {
|
||||
- "ip":"10.0.255.2",
|
||||
- "afi":"ipv4",
|
||||
- "interfaceName":"eth-rt2",
|
||||
- "active":true,
|
||||
- "onLink":true,
|
||||
- "labels":"*"
|
||||
+ "onLink":true
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -151,20 +99,7 @@
|
||||
"afi":"ipv4",
|
||||
"interfaceName":"eth-rt2",
|
||||
"active":true,
|
||||
- "onLink":true,
|
||||
- "backupIndex":[
|
||||
- 0
|
||||
- ]
|
||||
- }
|
||||
- ],
|
||||
- "backupNexthops":[
|
||||
- {
|
||||
- "ip":"10.0.255.3",
|
||||
- "afi":"ipv4",
|
||||
- "interfaceName":"eth-rt3",
|
||||
- "active":true,
|
||||
- "onLink":true,
|
||||
- "labels":"*"
|
||||
+ "onLink":true
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -185,20 +120,7 @@
|
||||
"afi":"ipv4",
|
||||
"interfaceName":"eth-rt3",
|
||||
"active":true,
|
||||
- "onLink":true,
|
||||
- "backupIndex":[
|
||||
- 0
|
||||
- ]
|
||||
- }
|
||||
- ],
|
||||
- "backupNexthops":[
|
||||
- {
|
||||
- "ip":"10.0.255.2",
|
||||
- "afi":"ipv4",
|
||||
- "interfaceName":"eth-rt2",
|
||||
- "active":true,
|
||||
- "onLink":true,
|
||||
- "labels":"*"
|
||||
+ "onLink":true
|
||||
}
|
||||
]
|
||||
}
|
@ -0,0 +1,122 @@
|
||||
--- a/rt1/step1/show_ipv6_route.ref
|
||||
+++ b/rt1/step2/show_ipv6_route.ref
|
||||
@@ -13,18 +13,7 @@
|
||||
"fib":true,
|
||||
"afi":"ipv6",
|
||||
"interfaceName":"eth-rt2",
|
||||
- "active":true,
|
||||
- "backupIndex":[
|
||||
- 0
|
||||
- ]
|
||||
- }
|
||||
- ],
|
||||
- "backupNexthops":[
|
||||
- {
|
||||
- "afi":"ipv6",
|
||||
- "interfaceName":"eth-rt3",
|
||||
- "active":true,
|
||||
- "labels":"*"
|
||||
+ "active":true
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -43,18 +32,7 @@
|
||||
"fib":true,
|
||||
"afi":"ipv6",
|
||||
"interfaceName":"eth-rt3",
|
||||
- "active":true,
|
||||
- "backupIndex":[
|
||||
- 0
|
||||
- ]
|
||||
- }
|
||||
- ],
|
||||
- "backupNexthops":[
|
||||
- {
|
||||
- "afi":"ipv6",
|
||||
- "interfaceName":"eth-rt2",
|
||||
- "active":true,
|
||||
- "labels":"*"
|
||||
+ "active":true
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -73,18 +51,7 @@
|
||||
"fib":true,
|
||||
"afi":"ipv6",
|
||||
"interfaceName":"eth-rt2",
|
||||
- "active":true,
|
||||
- "backupIndex":[
|
||||
- 0
|
||||
- ]
|
||||
- }
|
||||
- ],
|
||||
- "backupNexthops":[
|
||||
- {
|
||||
- "afi":"ipv6",
|
||||
- "interfaceName":"eth-rt3",
|
||||
- "active":true,
|
||||
- "labels":"*"
|
||||
+ "active":true
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -103,18 +70,7 @@
|
||||
"fib":true,
|
||||
"afi":"ipv6",
|
||||
"interfaceName":"eth-rt3",
|
||||
- "active":true,
|
||||
- "backupIndex":[
|
||||
- 0
|
||||
- ]
|
||||
- }
|
||||
- ],
|
||||
- "backupNexthops":[
|
||||
- {
|
||||
- "afi":"ipv6",
|
||||
- "interfaceName":"eth-rt2",
|
||||
- "active":true,
|
||||
- "labels":"*"
|
||||
+ "active":true
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -133,18 +89,7 @@
|
||||
"fib":true,
|
||||
"afi":"ipv6",
|
||||
"interfaceName":"eth-rt2",
|
||||
- "active":true,
|
||||
- "backupIndex":[
|
||||
- 0
|
||||
- ]
|
||||
- }
|
||||
- ],
|
||||
- "backupNexthops":[
|
||||
- {
|
||||
- "afi":"ipv6",
|
||||
- "interfaceName":"eth-rt3",
|
||||
- "active":true,
|
||||
- "labels":"*"
|
||||
+ "active":true
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -163,18 +108,7 @@
|
||||
"fib":true,
|
||||
"afi":"ipv6",
|
||||
"interfaceName":"eth-rt3",
|
||||
- "active":true,
|
||||
- "backupIndex":[
|
||||
- 0
|
||||
- ]
|
||||
- }
|
||||
- ],
|
||||
- "backupNexthops":[
|
||||
- {
|
||||
- "afi":"ipv6",
|
||||
- "interfaceName":"eth-rt2",
|
||||
- "active":true,
|
||||
- "labels":"*"
|
||||
+ "active":true
|
||||
}
|
||||
]
|
||||
}
|
134
tests/topotests/isis-rlfa-topo1/rt1/step3/show_ip_route.ref.diff
Normal file
134
tests/topotests/isis-rlfa-topo1/rt1/step3/show_ip_route.ref.diff
Normal file
@ -0,0 +1,134 @@
|
||||
--- a/rt1/step2/show_ip_route.ref
|
||||
+++ b/rt1/step3/show_ip_route.ref
|
||||
@@ -15,7 +15,20 @@
|
||||
"afi":"ipv4",
|
||||
"interfaceName":"eth-rt2",
|
||||
"active":true,
|
||||
- "onLink":true
|
||||
+ "onLink":true,
|
||||
+ "backupIndex":[
|
||||
+ 0
|
||||
+ ]
|
||||
+ }
|
||||
+ ],
|
||||
+ "backupNexthops":[
|
||||
+ {
|
||||
+ "ip":"10.0.255.3",
|
||||
+ "afi":"ipv4",
|
||||
+ "interfaceName":"eth-rt3",
|
||||
+ "active":true,
|
||||
+ "onLink":true,
|
||||
+ "labels":"*"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -36,7 +49,20 @@
|
||||
"afi":"ipv4",
|
||||
"interfaceName":"eth-rt3",
|
||||
"active":true,
|
||||
- "onLink":true
|
||||
+ "onLink":true,
|
||||
+ "backupIndex":[
|
||||
+ 0
|
||||
+ ]
|
||||
+ }
|
||||
+ ],
|
||||
+ "backupNexthops":[
|
||||
+ {
|
||||
+ "ip":"10.0.255.2",
|
||||
+ "afi":"ipv4",
|
||||
+ "interfaceName":"eth-rt2",
|
||||
+ "active":true,
|
||||
+ "onLink":true,
|
||||
+ "labels":"*"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -57,7 +83,20 @@
|
||||
"afi":"ipv4",
|
||||
"interfaceName":"eth-rt2",
|
||||
"active":true,
|
||||
- "onLink":true
|
||||
+ "onLink":true,
|
||||
+ "backupIndex":[
|
||||
+ 0
|
||||
+ ]
|
||||
+ }
|
||||
+ ],
|
||||
+ "backupNexthops":[
|
||||
+ {
|
||||
+ "ip":"10.0.255.3",
|
||||
+ "afi":"ipv4",
|
||||
+ "interfaceName":"eth-rt3",
|
||||
+ "active":true,
|
||||
+ "onLink":true,
|
||||
+ "labels":"*"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -78,7 +117,20 @@
|
||||
"afi":"ipv4",
|
||||
"interfaceName":"eth-rt3",
|
||||
"active":true,
|
||||
- "onLink":true
|
||||
+ "onLink":true,
|
||||
+ "backupIndex":[
|
||||
+ 0
|
||||
+ ]
|
||||
+ }
|
||||
+ ],
|
||||
+ "backupNexthops":[
|
||||
+ {
|
||||
+ "ip":"10.0.255.2",
|
||||
+ "afi":"ipv4",
|
||||
+ "interfaceName":"eth-rt2",
|
||||
+ "active":true,
|
||||
+ "onLink":true,
|
||||
+ "labels":"*"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -99,7 +151,20 @@
|
||||
"afi":"ipv4",
|
||||
"interfaceName":"eth-rt2",
|
||||
"active":true,
|
||||
- "onLink":true
|
||||
+ "onLink":true,
|
||||
+ "backupIndex":[
|
||||
+ 0
|
||||
+ ]
|
||||
+ }
|
||||
+ ],
|
||||
+ "backupNexthops":[
|
||||
+ {
|
||||
+ "ip":"10.0.255.3",
|
||||
+ "afi":"ipv4",
|
||||
+ "interfaceName":"eth-rt3",
|
||||
+ "active":true,
|
||||
+ "onLink":true,
|
||||
+ "labels":"*"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -120,7 +185,20 @@
|
||||
"afi":"ipv4",
|
||||
"interfaceName":"eth-rt3",
|
||||
"active":true,
|
||||
- "onLink":true
|
||||
+ "onLink":true,
|
||||
+ "backupIndex":[
|
||||
+ 0
|
||||
+ ]
|
||||
+ }
|
||||
+ ],
|
||||
+ "backupNexthops":[
|
||||
+ {
|
||||
+ "ip":"10.0.255.2",
|
||||
+ "afi":"ipv4",
|
||||
+ "interfaceName":"eth-rt2",
|
||||
+ "active":true,
|
||||
+ "onLink":true,
|
||||
+ "labels":"*"
|
||||
}
|
||||
]
|
||||
}
|
@ -0,0 +1,122 @@
|
||||
--- a/rt1/step2/show_ipv6_route.ref
|
||||
+++ b/rt1/step3/show_ipv6_route.ref
|
||||
@@ -13,7 +13,18 @@
|
||||
"fib":true,
|
||||
"afi":"ipv6",
|
||||
"interfaceName":"eth-rt2",
|
||||
- "active":true
|
||||
+ "active":true,
|
||||
+ "backupIndex":[
|
||||
+ 0
|
||||
+ ]
|
||||
+ }
|
||||
+ ],
|
||||
+ "backupNexthops":[
|
||||
+ {
|
||||
+ "afi":"ipv6",
|
||||
+ "interfaceName":"eth-rt3",
|
||||
+ "active":true,
|
||||
+ "labels":"*"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -32,7 +43,18 @@
|
||||
"fib":true,
|
||||
"afi":"ipv6",
|
||||
"interfaceName":"eth-rt3",
|
||||
- "active":true
|
||||
+ "active":true,
|
||||
+ "backupIndex":[
|
||||
+ 0
|
||||
+ ]
|
||||
+ }
|
||||
+ ],
|
||||
+ "backupNexthops":[
|
||||
+ {
|
||||
+ "afi":"ipv6",
|
||||
+ "interfaceName":"eth-rt2",
|
||||
+ "active":true,
|
||||
+ "labels":"*"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -51,7 +73,18 @@
|
||||
"fib":true,
|
||||
"afi":"ipv6",
|
||||
"interfaceName":"eth-rt2",
|
||||
- "active":true
|
||||
+ "active":true,
|
||||
+ "backupIndex":[
|
||||
+ 0
|
||||
+ ]
|
||||
+ }
|
||||
+ ],
|
||||
+ "backupNexthops":[
|
||||
+ {
|
||||
+ "afi":"ipv6",
|
||||
+ "interfaceName":"eth-rt3",
|
||||
+ "active":true,
|
||||
+ "labels":"*"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -70,7 +103,18 @@
|
||||
"fib":true,
|
||||
"afi":"ipv6",
|
||||
"interfaceName":"eth-rt3",
|
||||
- "active":true
|
||||
+ "active":true,
|
||||
+ "backupIndex":[
|
||||
+ 0
|
||||
+ ]
|
||||
+ }
|
||||
+ ],
|
||||
+ "backupNexthops":[
|
||||
+ {
|
||||
+ "afi":"ipv6",
|
||||
+ "interfaceName":"eth-rt2",
|
||||
+ "active":true,
|
||||
+ "labels":"*"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -89,7 +133,18 @@
|
||||
"fib":true,
|
||||
"afi":"ipv6",
|
||||
"interfaceName":"eth-rt2",
|
||||
- "active":true
|
||||
+ "active":true,
|
||||
+ "backupIndex":[
|
||||
+ 0
|
||||
+ ]
|
||||
+ }
|
||||
+ ],
|
||||
+ "backupNexthops":[
|
||||
+ {
|
||||
+ "afi":"ipv6",
|
||||
+ "interfaceName":"eth-rt3",
|
||||
+ "active":true,
|
||||
+ "labels":"*"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -108,7 +163,18 @@
|
||||
"fib":true,
|
||||
"afi":"ipv6",
|
||||
"interfaceName":"eth-rt3",
|
||||
- "active":true
|
||||
+ "active":true,
|
||||
+ "backupIndex":[
|
||||
+ 0
|
||||
+ ]
|
||||
+ }
|
||||
+ ],
|
||||
+ "backupNexthops":[
|
||||
+ {
|
||||
+ "afi":"ipv6",
|
||||
+ "interfaceName":"eth-rt2",
|
||||
+ "active":true,
|
||||
+ "labels":"*"
|
||||
}
|
||||
]
|
||||
}
|
@ -0,0 +1,68 @@
|
||||
--- a/rt1/step3/show_ip_route.ref
|
||||
+++ b/rt1/step4/show_ip_route.ref
|
||||
@@ -15,20 +15,7 @@
|
||||
"afi":"ipv4",
|
||||
"interfaceName":"eth-rt2",
|
||||
"active":true,
|
||||
- "onLink":true,
|
||||
- "backupIndex":[
|
||||
- 0
|
||||
- ]
|
||||
- }
|
||||
- ],
|
||||
- "backupNexthops":[
|
||||
- {
|
||||
- "ip":"10.0.255.3",
|
||||
- "afi":"ipv4",
|
||||
- "interfaceName":"eth-rt3",
|
||||
- "active":true,
|
||||
- "onLink":true,
|
||||
- "labels":"*"
|
||||
+ "onLink":true
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -83,20 +70,7 @@
|
||||
"afi":"ipv4",
|
||||
"interfaceName":"eth-rt2",
|
||||
"active":true,
|
||||
- "onLink":true,
|
||||
- "backupIndex":[
|
||||
- 0
|
||||
- ]
|
||||
- }
|
||||
- ],
|
||||
- "backupNexthops":[
|
||||
- {
|
||||
- "ip":"10.0.255.3",
|
||||
- "afi":"ipv4",
|
||||
- "interfaceName":"eth-rt3",
|
||||
- "active":true,
|
||||
- "onLink":true,
|
||||
- "labels":"*"
|
||||
+ "onLink":true
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -151,20 +125,7 @@
|
||||
"afi":"ipv4",
|
||||
"interfaceName":"eth-rt2",
|
||||
"active":true,
|
||||
- "onLink":true,
|
||||
- "backupIndex":[
|
||||
- 0
|
||||
- ]
|
||||
- }
|
||||
- ],
|
||||
- "backupNexthops":[
|
||||
- {
|
||||
- "ip":"10.0.255.3",
|
||||
- "afi":"ipv4",
|
||||
- "interfaceName":"eth-rt3",
|
||||
- "active":true,
|
||||
- "onLink":true,
|
||||
- "labels":"*"
|
||||
+ "onLink":true
|
||||
}
|
||||
]
|
||||
}
|
@ -0,0 +1,62 @@
|
||||
--- a/rt1/step3/show_ipv6_route.ref
|
||||
+++ b/rt1/step4/show_ipv6_route.ref
|
||||
@@ -13,18 +13,7 @@
|
||||
"fib":true,
|
||||
"afi":"ipv6",
|
||||
"interfaceName":"eth-rt2",
|
||||
- "active":true,
|
||||
- "backupIndex":[
|
||||
- 0
|
||||
- ]
|
||||
- }
|
||||
- ],
|
||||
- "backupNexthops":[
|
||||
- {
|
||||
- "afi":"ipv6",
|
||||
- "interfaceName":"eth-rt3",
|
||||
- "active":true,
|
||||
- "labels":"*"
|
||||
+ "active":true
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -73,18 +62,7 @@
|
||||
"fib":true,
|
||||
"afi":"ipv6",
|
||||
"interfaceName":"eth-rt2",
|
||||
- "active":true,
|
||||
- "backupIndex":[
|
||||
- 0
|
||||
- ]
|
||||
- }
|
||||
- ],
|
||||
- "backupNexthops":[
|
||||
- {
|
||||
- "afi":"ipv6",
|
||||
- "interfaceName":"eth-rt3",
|
||||
- "active":true,
|
||||
- "labels":"*"
|
||||
+ "active":true
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -133,18 +111,7 @@
|
||||
"fib":true,
|
||||
"afi":"ipv6",
|
||||
"interfaceName":"eth-rt2",
|
||||
- "active":true,
|
||||
- "backupIndex":[
|
||||
- 0
|
||||
- ]
|
||||
- }
|
||||
- ],
|
||||
- "backupNexthops":[
|
||||
- {
|
||||
- "afi":"ipv6",
|
||||
- "interfaceName":"eth-rt3",
|
||||
- "active":true,
|
||||
- "labels":"*"
|
||||
+ "active":true
|
||||
}
|
||||
]
|
||||
}
|
@ -0,0 +1,68 @@
|
||||
--- a/rt1/step4/show_ip_route.ref
|
||||
+++ b/rt1/step5/show_ip_route.ref
|
||||
@@ -36,20 +36,7 @@
|
||||
"afi":"ipv4",
|
||||
"interfaceName":"eth-rt3",
|
||||
"active":true,
|
||||
- "onLink":true,
|
||||
- "backupIndex":[
|
||||
- 0
|
||||
- ]
|
||||
- }
|
||||
- ],
|
||||
- "backupNexthops":[
|
||||
- {
|
||||
- "ip":"10.0.255.2",
|
||||
- "afi":"ipv4",
|
||||
- "interfaceName":"eth-rt2",
|
||||
- "active":true,
|
||||
- "onLink":true,
|
||||
- "labels":"*"
|
||||
+ "onLink":true
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -91,20 +78,7 @@
|
||||
"afi":"ipv4",
|
||||
"interfaceName":"eth-rt3",
|
||||
"active":true,
|
||||
- "onLink":true,
|
||||
- "backupIndex":[
|
||||
- 0
|
||||
- ]
|
||||
- }
|
||||
- ],
|
||||
- "backupNexthops":[
|
||||
- {
|
||||
- "ip":"10.0.255.2",
|
||||
- "afi":"ipv4",
|
||||
- "interfaceName":"eth-rt2",
|
||||
- "active":true,
|
||||
- "onLink":true,
|
||||
- "labels":"*"
|
||||
+ "onLink":true
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -146,20 +120,7 @@
|
||||
"afi":"ipv4",
|
||||
"interfaceName":"eth-rt3",
|
||||
"active":true,
|
||||
- "onLink":true,
|
||||
- "backupIndex":[
|
||||
- 0
|
||||
- ]
|
||||
- }
|
||||
- ],
|
||||
- "backupNexthops":[
|
||||
- {
|
||||
- "ip":"10.0.255.2",
|
||||
- "afi":"ipv4",
|
||||
- "interfaceName":"eth-rt2",
|
||||
- "active":true,
|
||||
- "onLink":true,
|
||||
- "labels":"*"
|
||||
+ "onLink":true
|
||||
}
|
||||
]
|
||||
}
|
@ -0,0 +1,62 @@
|
||||
--- a/rt1/step4/show_ipv6_route.ref
|
||||
+++ b/rt1/step5/show_ipv6_route.ref
|
||||
@@ -32,18 +32,7 @@
|
||||
"fib":true,
|
||||
"afi":"ipv6",
|
||||
"interfaceName":"eth-rt3",
|
||||
- "active":true,
|
||||
- "backupIndex":[
|
||||
- 0
|
||||
- ]
|
||||
- }
|
||||
- ],
|
||||
- "backupNexthops":[
|
||||
- {
|
||||
- "afi":"ipv6",
|
||||
- "interfaceName":"eth-rt2",
|
||||
- "active":true,
|
||||
- "labels":"*"
|
||||
+ "active":true
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -81,18 +70,7 @@
|
||||
"fib":true,
|
||||
"afi":"ipv6",
|
||||
"interfaceName":"eth-rt3",
|
||||
- "active":true,
|
||||
- "backupIndex":[
|
||||
- 0
|
||||
- ]
|
||||
- }
|
||||
- ],
|
||||
- "backupNexthops":[
|
||||
- {
|
||||
- "afi":"ipv6",
|
||||
- "interfaceName":"eth-rt2",
|
||||
- "active":true,
|
||||
- "labels":"*"
|
||||
+ "active":true
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -130,18 +108,7 @@
|
||||
"fib":true,
|
||||
"afi":"ipv6",
|
||||
"interfaceName":"eth-rt3",
|
||||
- "active":true,
|
||||
- "backupIndex":[
|
||||
- 0
|
||||
- ]
|
||||
- }
|
||||
- ],
|
||||
- "backupNexthops":[
|
||||
- {
|
||||
- "afi":"ipv6",
|
||||
- "interfaceName":"eth-rt2",
|
||||
- "active":true,
|
||||
- "labels":"*"
|
||||
+ "active":true
|
||||
}
|
||||
]
|
||||
}
|
134
tests/topotests/isis-rlfa-topo1/rt1/step6/show_ip_route.ref.diff
Normal file
134
tests/topotests/isis-rlfa-topo1/rt1/step6/show_ip_route.ref.diff
Normal file
@ -0,0 +1,134 @@
|
||||
--- a/rt1/step5/show_ip_route.ref
|
||||
+++ b/rt1/step6/show_ip_route.ref
|
||||
@@ -15,7 +15,20 @@
|
||||
"afi":"ipv4",
|
||||
"interfaceName":"eth-rt2",
|
||||
"active":true,
|
||||
- "onLink":true
|
||||
+ "onLink":true,
|
||||
+ "backupIndex":[
|
||||
+ 0
|
||||
+ ]
|
||||
+ }
|
||||
+ ],
|
||||
+ "backupNexthops":[
|
||||
+ {
|
||||
+ "ip":"10.0.255.3",
|
||||
+ "afi":"ipv4",
|
||||
+ "interfaceName":"eth-rt3",
|
||||
+ "active":true,
|
||||
+ "onLink":true,
|
||||
+ "labels":"*"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -36,7 +49,20 @@
|
||||
"afi":"ipv4",
|
||||
"interfaceName":"eth-rt3",
|
||||
"active":true,
|
||||
- "onLink":true
|
||||
+ "onLink":true,
|
||||
+ "backupIndex":[
|
||||
+ 0
|
||||
+ ]
|
||||
+ }
|
||||
+ ],
|
||||
+ "backupNexthops":[
|
||||
+ {
|
||||
+ "ip":"10.0.255.2",
|
||||
+ "afi":"ipv4",
|
||||
+ "interfaceName":"eth-rt2",
|
||||
+ "active":true,
|
||||
+ "onLink":true,
|
||||
+ "labels":"*"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -57,7 +83,20 @@
|
||||
"afi":"ipv4",
|
||||
"interfaceName":"eth-rt2",
|
||||
"active":true,
|
||||
- "onLink":true
|
||||
+ "onLink":true,
|
||||
+ "backupIndex":[
|
||||
+ 0
|
||||
+ ]
|
||||
+ }
|
||||
+ ],
|
||||
+ "backupNexthops":[
|
||||
+ {
|
||||
+ "ip":"10.0.255.3",
|
||||
+ "afi":"ipv4",
|
||||
+ "interfaceName":"eth-rt3",
|
||||
+ "active":true,
|
||||
+ "onLink":true,
|
||||
+ "labels":"*"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -78,7 +117,20 @@
|
||||
"afi":"ipv4",
|
||||
"interfaceName":"eth-rt3",
|
||||
"active":true,
|
||||
- "onLink":true
|
||||
+ "onLink":true,
|
||||
+ "backupIndex":[
|
||||
+ 0
|
||||
+ ]
|
||||
+ }
|
||||
+ ],
|
||||
+ "backupNexthops":[
|
||||
+ {
|
||||
+ "ip":"10.0.255.2",
|
||||
+ "afi":"ipv4",
|
||||
+ "interfaceName":"eth-rt2",
|
||||
+ "active":true,
|
||||
+ "onLink":true,
|
||||
+ "labels":"*"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -99,7 +151,20 @@
|
||||
"afi":"ipv4",
|
||||
"interfaceName":"eth-rt2",
|
||||
"active":true,
|
||||
- "onLink":true
|
||||
+ "onLink":true,
|
||||
+ "backupIndex":[
|
||||
+ 0
|
||||
+ ]
|
||||
+ }
|
||||
+ ],
|
||||
+ "backupNexthops":[
|
||||
+ {
|
||||
+ "ip":"10.0.255.3",
|
||||
+ "afi":"ipv4",
|
||||
+ "interfaceName":"eth-rt3",
|
||||
+ "active":true,
|
||||
+ "onLink":true,
|
||||
+ "labels":"*"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -120,7 +185,20 @@
|
||||
"afi":"ipv4",
|
||||
"interfaceName":"eth-rt3",
|
||||
"active":true,
|
||||
- "onLink":true
|
||||
+ "onLink":true,
|
||||
+ "backupIndex":[
|
||||
+ 0
|
||||
+ ]
|
||||
+ }
|
||||
+ ],
|
||||
+ "backupNexthops":[
|
||||
+ {
|
||||
+ "ip":"10.0.255.2",
|
||||
+ "afi":"ipv4",
|
||||
+ "interfaceName":"eth-rt2",
|
||||
+ "active":true,
|
||||
+ "onLink":true,
|
||||
+ "labels":"*"
|
||||
}
|
||||
]
|
||||
}
|
@ -0,0 +1,122 @@
|
||||
--- a/rt1/step5/show_ipv6_route.ref
|
||||
+++ b/rt1/step6/show_ipv6_route.ref
|
||||
@@ -13,7 +13,18 @@
|
||||
"fib":true,
|
||||
"afi":"ipv6",
|
||||
"interfaceName":"eth-rt2",
|
||||
- "active":true
|
||||
+ "active":true,
|
||||
+ "backupIndex":[
|
||||
+ 0
|
||||
+ ]
|
||||
+ }
|
||||
+ ],
|
||||
+ "backupNexthops":[
|
||||
+ {
|
||||
+ "afi":"ipv6",
|
||||
+ "interfaceName":"eth-rt3",
|
||||
+ "active":true,
|
||||
+ "labels":"*"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -32,7 +43,18 @@
|
||||
"fib":true,
|
||||
"afi":"ipv6",
|
||||
"interfaceName":"eth-rt3",
|
||||
- "active":true
|
||||
+ "active":true,
|
||||
+ "backupIndex":[
|
||||
+ 0
|
||||
+ ]
|
||||
+ }
|
||||
+ ],
|
||||
+ "backupNexthops":[
|
||||
+ {
|
||||
+ "afi":"ipv6",
|
||||
+ "interfaceName":"eth-rt2",
|
||||
+ "active":true,
|
||||
+ "labels":"*"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -51,7 +73,18 @@
|
||||
"fib":true,
|
||||
"afi":"ipv6",
|
||||
"interfaceName":"eth-rt2",
|
||||
- "active":true
|
||||
+ "active":true,
|
||||
+ "backupIndex":[
|
||||
+ 0
|
||||
+ ]
|
||||
+ }
|
||||
+ ],
|
||||
+ "backupNexthops":[
|
||||
+ {
|
||||
+ "afi":"ipv6",
|
||||
+ "interfaceName":"eth-rt3",
|
||||
+ "active":true,
|
||||
+ "labels":"*"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -70,7 +103,18 @@
|
||||
"fib":true,
|
||||
"afi":"ipv6",
|
||||
"interfaceName":"eth-rt3",
|
||||
- "active":true
|
||||
+ "active":true,
|
||||
+ "backupIndex":[
|
||||
+ 0
|
||||
+ ]
|
||||
+ }
|
||||
+ ],
|
||||
+ "backupNexthops":[
|
||||
+ {
|
||||
+ "afi":"ipv6",
|
||||
+ "interfaceName":"eth-rt2",
|
||||
+ "active":true,
|
||||
+ "labels":"*"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -89,7 +133,18 @@
|
||||
"fib":true,
|
||||
"afi":"ipv6",
|
||||
"interfaceName":"eth-rt2",
|
||||
- "active":true
|
||||
+ "active":true,
|
||||
+ "backupIndex":[
|
||||
+ 0
|
||||
+ ]
|
||||
+ }
|
||||
+ ],
|
||||
+ "backupNexthops":[
|
||||
+ {
|
||||
+ "afi":"ipv6",
|
||||
+ "interfaceName":"eth-rt3",
|
||||
+ "active":true,
|
||||
+ "labels":"*"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -108,7 +163,18 @@
|
||||
"fib":true,
|
||||
"afi":"ipv6",
|
||||
"interfaceName":"eth-rt3",
|
||||
- "active":true
|
||||
+ "active":true,
|
||||
+ "backupIndex":[
|
||||
+ 0
|
||||
+ ]
|
||||
+ }
|
||||
+ ],
|
||||
+ "backupNexthops":[
|
||||
+ {
|
||||
+ "afi":"ipv6",
|
||||
+ "interfaceName":"eth-rt2",
|
||||
+ "active":true,
|
||||
+ "labels":"*"
|
||||
}
|
||||
]
|
||||
}
|
@ -0,0 +1,68 @@
|
||||
--- a/rt1/step8/show_ip_route.ref
|
||||
+++ b/rt1/step9/show_ip_route.ref
|
||||
@@ -15,20 +15,7 @@
|
||||
"afi":"ipv4",
|
||||
"interfaceName":"eth-rt2",
|
||||
"active":true,
|
||||
- "onLink":true,
|
||||
- "backupIndex":[
|
||||
- 0
|
||||
- ]
|
||||
- }
|
||||
- ],
|
||||
- "backupNexthops":[
|
||||
- {
|
||||
- "ip":"10.0.255.3",
|
||||
- "afi":"ipv4",
|
||||
- "interfaceName":"eth-rt3",
|
||||
- "active":true,
|
||||
- "onLink":true,
|
||||
- "labels":"*"
|
||||
+ "onLink":true
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -83,20 +70,7 @@
|
||||
"afi":"ipv4",
|
||||
"interfaceName":"eth-rt2",
|
||||
"active":true,
|
||||
- "onLink":true,
|
||||
- "backupIndex":[
|
||||
- 0
|
||||
- ]
|
||||
- }
|
||||
- ],
|
||||
- "backupNexthops":[
|
||||
- {
|
||||
- "ip":"10.0.255.3",
|
||||
- "afi":"ipv4",
|
||||
- "interfaceName":"eth-rt3",
|
||||
- "active":true,
|
||||
- "onLink":true,
|
||||
- "labels":"*"
|
||||
+ "onLink":true
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -151,20 +125,7 @@
|
||||
"afi":"ipv4",
|
||||
"interfaceName":"eth-rt2",
|
||||
"active":true,
|
||||
- "onLink":true,
|
||||
- "backupIndex":[
|
||||
- 0
|
||||
- ]
|
||||
- }
|
||||
- ],
|
||||
- "backupNexthops":[
|
||||
- {
|
||||
- "ip":"10.0.255.3",
|
||||
- "afi":"ipv4",
|
||||
- "interfaceName":"eth-rt3",
|
||||
- "active":true,
|
||||
- "onLink":true,
|
||||
- "labels":"*"
|
||||
+ "onLink":true
|
||||
}
|
||||
]
|
||||
}
|
@ -0,0 +1,62 @@
|
||||
--- a/rt1/step8/show_ipv6_route.ref
|
||||
+++ b/rt1/step9/show_ipv6_route.ref
|
||||
@@ -13,18 +13,7 @@
|
||||
"fib":true,
|
||||
"afi":"ipv6",
|
||||
"interfaceName":"eth-rt2",
|
||||
- "active":true,
|
||||
- "backupIndex":[
|
||||
- 0
|
||||
- ]
|
||||
- }
|
||||
- ],
|
||||
- "backupNexthops":[
|
||||
- {
|
||||
- "afi":"ipv6",
|
||||
- "interfaceName":"eth-rt3",
|
||||
- "active":true,
|
||||
- "labels":"*"
|
||||
+ "active":true
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -73,18 +62,7 @@
|
||||
"fib":true,
|
||||
"afi":"ipv6",
|
||||
"interfaceName":"eth-rt2",
|
||||
- "active":true,
|
||||
- "backupIndex":[
|
||||
- 0
|
||||
- ]
|
||||
- }
|
||||
- ],
|
||||
- "backupNexthops":[
|
||||
- {
|
||||
- "afi":"ipv6",
|
||||
- "interfaceName":"eth-rt3",
|
||||
- "active":true,
|
||||
- "labels":"*"
|
||||
+ "active":true
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -133,18 +111,7 @@
|
||||
"fib":true,
|
||||
"afi":"ipv6",
|
||||
"interfaceName":"eth-rt2",
|
||||
- "active":true,
|
||||
- "backupIndex":[
|
||||
- 0
|
||||
- ]
|
||||
- }
|
||||
- ],
|
||||
- "backupNexthops":[
|
||||
- {
|
||||
- "afi":"ipv6",
|
||||
- "interfaceName":"eth-rt3",
|
||||
- "active":true,
|
||||
- "labels":"*"
|
||||
+ "active":true
|
||||
}
|
||||
]
|
||||
}
|
22
tests/topotests/isis-rlfa-topo1/rt1/zebra.conf
Normal file
22
tests/topotests/isis-rlfa-topo1/rt1/zebra.conf
Normal file
@ -0,0 +1,22 @@
|
||||
log file zebra.log
|
||||
!
|
||||
hostname rt1
|
||||
!
|
||||
debug zebra kernel
|
||||
debug zebra packet
|
||||
debug zebra mpls
|
||||
!
|
||||
interface lo
|
||||
ip address 10.0.255.1/32
|
||||
ipv6 address 2001:db8::1/128
|
||||
!
|
||||
interface eth-rt2
|
||||
ip address 10.0.255.1/32
|
||||
!
|
||||
interface eth-rt3
|
||||
ip address 10.0.255.1/32
|
||||
!
|
||||
ip forwarding
|
||||
!
|
||||
line vty
|
||||
!
|
32
tests/topotests/isis-rlfa-topo1/rt2/isisd.conf
Normal file
32
tests/topotests/isis-rlfa-topo1/rt2/isisd.conf
Normal file
@ -0,0 +1,32 @@
|
||||
password 1
|
||||
hostname rt2
|
||||
log file isisd.log
|
||||
!
|
||||
debug isis events
|
||||
debug isis route-events
|
||||
debug isis spf-events
|
||||
debug isis lsp-gen
|
||||
!
|
||||
interface lo
|
||||
ip router isis 1
|
||||
ipv6 router isis 1
|
||||
isis passive
|
||||
!
|
||||
interface eth-rt1
|
||||
ip router isis 1
|
||||
ipv6 router isis 1
|
||||
isis hello-multiplier 3
|
||||
isis network point-to-point
|
||||
!
|
||||
interface eth-rt4
|
||||
ip router isis 1
|
||||
ipv6 router isis 1
|
||||
isis hello-multiplier 3
|
||||
isis network point-to-point
|
||||
!
|
||||
router isis 1
|
||||
net 49.0000.0000.0000.0002.00
|
||||
is-type level-1-2
|
||||
lsp-gen-interval 2
|
||||
topology ipv6-unicast
|
||||
!
|
30
tests/topotests/isis-rlfa-topo1/rt2/ldpd.conf
Normal file
30
tests/topotests/isis-rlfa-topo1/rt2/ldpd.conf
Normal file
@ -0,0 +1,30 @@
|
||||
log file ldpd.log
|
||||
!
|
||||
hostname rt2
|
||||
!
|
||||
debug mpls ldp messages recv
|
||||
debug mpls ldp messages sent
|
||||
debug mpls ldp zebra
|
||||
!
|
||||
mpls ldp
|
||||
router-id 10.0.255.2
|
||||
dual-stack transport-connection prefer ipv4
|
||||
!
|
||||
address-family ipv4
|
||||
label local allocate host-routes
|
||||
discovery targeted-hello accept
|
||||
discovery transport-address 10.0.255.2
|
||||
!
|
||||
interface eth-rt1
|
||||
interface eth-rt4
|
||||
!
|
||||
!
|
||||
address-family ipv6
|
||||
label local allocate host-routes
|
||||
discovery transport-address 2001:db8::2
|
||||
!
|
||||
interface eth-rt1
|
||||
interface eth-rt4
|
||||
!
|
||||
!
|
||||
!
|
22
tests/topotests/isis-rlfa-topo1/rt2/zebra.conf
Normal file
22
tests/topotests/isis-rlfa-topo1/rt2/zebra.conf
Normal file
@ -0,0 +1,22 @@
|
||||
log file zebra.log
|
||||
!
|
||||
hostname rt2
|
||||
!
|
||||
debug zebra kernel
|
||||
debug zebra packet
|
||||
debug zebra mpls
|
||||
!
|
||||
interface lo
|
||||
ip address 10.0.255.2/32
|
||||
ipv6 address 2001:db8::2/128
|
||||
!
|
||||
interface eth-rt1
|
||||
ip address 10.0.255.2/32
|
||||
!
|
||||
interface eth-rt4
|
||||
ip address 10.0.255.2/32
|
||||
!
|
||||
ip forwarding
|
||||
!
|
||||
line vty
|
||||
!
|
32
tests/topotests/isis-rlfa-topo1/rt3/isisd.conf
Normal file
32
tests/topotests/isis-rlfa-topo1/rt3/isisd.conf
Normal file
@ -0,0 +1,32 @@
|
||||
password 1
|
||||
hostname rt3
|
||||
log file isisd.log
|
||||
!
|
||||
debug isis events
|
||||
debug isis route-events
|
||||
debug isis spf-events
|
||||
debug isis lsp-gen
|
||||
!
|
||||
interface lo
|
||||
ip router isis 1
|
||||
ipv6 router isis 1
|
||||
isis passive
|
||||
!
|
||||
interface eth-rt1
|
||||
ip router isis 1
|
||||
ipv6 router isis 1
|
||||
isis hello-multiplier 3
|
||||
isis network point-to-point
|
||||
!
|
||||
interface eth-rt5
|
||||
ip router isis 1
|
||||
ipv6 router isis 1
|
||||
isis hello-multiplier 3
|
||||
isis network point-to-point
|
||||
!
|
||||
router isis 1
|
||||
net 49.0000.0000.0000.0003.00
|
||||
is-type level-1-2
|
||||
lsp-gen-interval 2
|
||||
topology ipv6-unicast
|
||||
!
|
30
tests/topotests/isis-rlfa-topo1/rt3/ldpd.conf
Normal file
30
tests/topotests/isis-rlfa-topo1/rt3/ldpd.conf
Normal file
@ -0,0 +1,30 @@
|
||||
log file ldpd.log
|
||||
!
|
||||
hostname rt3
|
||||
!
|
||||
debug mpls ldp messages recv
|
||||
debug mpls ldp messages sent
|
||||
debug mpls ldp zebra
|
||||
!
|
||||
mpls ldp
|
||||
router-id 10.0.255.3
|
||||
dual-stack transport-connection prefer ipv4
|
||||
!
|
||||
address-family ipv4
|
||||
label local allocate host-routes
|
||||
discovery targeted-hello accept
|
||||
discovery transport-address 10.0.255.3
|
||||
!
|
||||
interface eth-rt1
|
||||
interface eth-rt5
|
||||
!
|
||||
!
|
||||
address-family ipv6
|
||||
label local allocate host-routes
|
||||
discovery transport-address 2001:db8::3
|
||||
!
|
||||
interface eth-rt1
|
||||
interface eth-rt5
|
||||
!
|
||||
!
|
||||
!
|
22
tests/topotests/isis-rlfa-topo1/rt3/zebra.conf
Normal file
22
tests/topotests/isis-rlfa-topo1/rt3/zebra.conf
Normal file
@ -0,0 +1,22 @@
|
||||
log file zebra.log
|
||||
!
|
||||
hostname rt3
|
||||
!
|
||||
debug zebra kernel
|
||||
debug zebra packet
|
||||
debug zebra mpls
|
||||
!
|
||||
interface lo
|
||||
ip address 10.0.255.3/32
|
||||
ipv6 address 2001:db8::3/128
|
||||
!
|
||||
interface eth-rt1
|
||||
ip address 10.0.255.3/32
|
||||
!
|
||||
interface eth-rt5
|
||||
ip address 10.0.255.3/32
|
||||
!
|
||||
ip forwarding
|
||||
!
|
||||
line vty
|
||||
!
|
32
tests/topotests/isis-rlfa-topo1/rt4/isisd.conf
Normal file
32
tests/topotests/isis-rlfa-topo1/rt4/isisd.conf
Normal file
@ -0,0 +1,32 @@
|
||||
password 1
|
||||
hostname rt4
|
||||
log file isisd.log
|
||||
!
|
||||
debug isis events
|
||||
debug isis route-events
|
||||
debug isis spf-events
|
||||
debug isis lsp-gen
|
||||
!
|
||||
interface lo
|
||||
ip router isis 1
|
||||
ipv6 router isis 1
|
||||
isis passive
|
||||
!
|
||||
interface eth-rt2
|
||||
ip router isis 1
|
||||
ipv6 router isis 1
|
||||
isis hello-multiplier 3
|
||||
isis network point-to-point
|
||||
!
|
||||
interface eth-rt6
|
||||
ip router isis 1
|
||||
ipv6 router isis 1
|
||||
isis hello-multiplier 3
|
||||
isis network point-to-point
|
||||
!
|
||||
router isis 1
|
||||
net 49.0000.0000.0000.0004.00
|
||||
is-type level-1-2
|
||||
lsp-gen-interval 2
|
||||
topology ipv6-unicast
|
||||
!
|
30
tests/topotests/isis-rlfa-topo1/rt4/ldpd.conf
Normal file
30
tests/topotests/isis-rlfa-topo1/rt4/ldpd.conf
Normal file
@ -0,0 +1,30 @@
|
||||
log file ldpd.log
|
||||
!
|
||||
hostname rt4
|
||||
!
|
||||
debug mpls ldp messages recv
|
||||
debug mpls ldp messages sent
|
||||
debug mpls ldp zebra
|
||||
!
|
||||
mpls ldp
|
||||
router-id 10.0.255.4
|
||||
dual-stack transport-connection prefer ipv4
|
||||
!
|
||||
address-family ipv4
|
||||
label local allocate host-routes
|
||||
discovery targeted-hello accept
|
||||
discovery transport-address 10.0.255.4
|
||||
!
|
||||
interface eth-rt2
|
||||
interface eth-rt6
|
||||
!
|
||||
!
|
||||
address-family ipv6
|
||||
label local allocate host-routes
|
||||
discovery transport-address 2001:db8::4
|
||||
!
|
||||
interface eth-rt2
|
||||
interface eth-rt6
|
||||
!
|
||||
!
|
||||
!
|
22
tests/topotests/isis-rlfa-topo1/rt4/zebra.conf
Normal file
22
tests/topotests/isis-rlfa-topo1/rt4/zebra.conf
Normal file
@ -0,0 +1,22 @@
|
||||
log file zebra.log
|
||||
!
|
||||
hostname rt4
|
||||
!
|
||||
debug zebra kernel
|
||||
debug zebra packet
|
||||
debug zebra mpls
|
||||
!
|
||||
interface lo
|
||||
ip address 10.0.255.4/32
|
||||
ipv6 address 2001:db8::4/128
|
||||
!
|
||||
interface eth-rt2
|
||||
ip address 10.0.255.4/32
|
||||
!
|
||||
interface eth-rt6
|
||||
ip address 10.0.255.4/32
|
||||
!
|
||||
ip forwarding
|
||||
!
|
||||
line vty
|
||||
!
|
32
tests/topotests/isis-rlfa-topo1/rt5/isisd.conf
Normal file
32
tests/topotests/isis-rlfa-topo1/rt5/isisd.conf
Normal file
@ -0,0 +1,32 @@
|
||||
password 1
|
||||
hostname rt5
|
||||
log file isisd.log
|
||||
!
|
||||
debug isis events
|
||||
debug isis route-events
|
||||
debug isis spf-events
|
||||
debug isis lsp-gen
|
||||
!
|
||||
interface lo
|
||||
ip router isis 1
|
||||
ipv6 router isis 1
|
||||
isis passive
|
||||
!
|
||||
interface eth-rt3
|
||||
ip router isis 1
|
||||
ipv6 router isis 1
|
||||
isis hello-multiplier 3
|
||||
isis network point-to-point
|
||||
!
|
||||
interface eth-rt7
|
||||
ip router isis 1
|
||||
ipv6 router isis 1
|
||||
isis hello-multiplier 3
|
||||
isis network point-to-point
|
||||
!
|
||||
router isis 1
|
||||
net 49.0000.0000.0000.0005.00
|
||||
is-type level-1-2
|
||||
lsp-gen-interval 2
|
||||
topology ipv6-unicast
|
||||
!
|
30
tests/topotests/isis-rlfa-topo1/rt5/ldpd.conf
Normal file
30
tests/topotests/isis-rlfa-topo1/rt5/ldpd.conf
Normal file
@ -0,0 +1,30 @@
|
||||
log file ldpd.log
|
||||
!
|
||||
hostname rt5
|
||||
!
|
||||
debug mpls ldp messages recv
|
||||
debug mpls ldp messages sent
|
||||
debug mpls ldp zebra
|
||||
!
|
||||
mpls ldp
|
||||
router-id 10.0.255.5
|
||||
dual-stack transport-connection prefer ipv4
|
||||
!
|
||||
address-family ipv4
|
||||
label local allocate host-routes
|
||||
discovery targeted-hello accept
|
||||
discovery transport-address 10.0.255.5
|
||||
!
|
||||
interface eth-rt3
|
||||
interface eth-rt7
|
||||
!
|
||||
!
|
||||
address-family ipv6
|
||||
label local allocate host-routes
|
||||
discovery transport-address 2001:db8::5
|
||||
!
|
||||
interface eth-rt3
|
||||
interface eth-rt7
|
||||
!
|
||||
!
|
||||
!
|
22
tests/topotests/isis-rlfa-topo1/rt5/zebra.conf
Normal file
22
tests/topotests/isis-rlfa-topo1/rt5/zebra.conf
Normal file
@ -0,0 +1,22 @@
|
||||
log file zebra.log
|
||||
!
|
||||
hostname rt5
|
||||
!
|
||||
debug zebra kernel
|
||||
debug zebra packet
|
||||
debug zebra mpls
|
||||
!
|
||||
interface lo
|
||||
ip address 10.0.255.5/32
|
||||
ipv6 address 2001:db8::5/128
|
||||
!
|
||||
interface eth-rt3
|
||||
ip address 10.0.255.5/32
|
||||
!
|
||||
interface eth-rt7
|
||||
ip address 10.0.255.5/32
|
||||
!
|
||||
ip forwarding
|
||||
!
|
||||
line vty
|
||||
!
|
32
tests/topotests/isis-rlfa-topo1/rt6/isisd.conf
Normal file
32
tests/topotests/isis-rlfa-topo1/rt6/isisd.conf
Normal file
@ -0,0 +1,32 @@
|
||||
password 1
|
||||
hostname rt6
|
||||
log file isisd.log
|
||||
!
|
||||
debug isis events
|
||||
debug isis route-events
|
||||
debug isis spf-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 hello-multiplier 3
|
||||
isis network point-to-point
|
||||
!
|
||||
interface eth-rt8
|
||||
ip router isis 1
|
||||
ipv6 router isis 1
|
||||
isis hello-multiplier 3
|
||||
isis network point-to-point
|
||||
!
|
||||
router isis 1
|
||||
net 49.0000.0000.0000.0006.00
|
||||
is-type level-1-2
|
||||
lsp-gen-interval 2
|
||||
topology ipv6-unicast
|
||||
!
|
30
tests/topotests/isis-rlfa-topo1/rt6/ldpd.conf
Normal file
30
tests/topotests/isis-rlfa-topo1/rt6/ldpd.conf
Normal file
@ -0,0 +1,30 @@
|
||||
log file ldpd.log
|
||||
!
|
||||
hostname rt6
|
||||
!
|
||||
debug mpls ldp messages recv
|
||||
debug mpls ldp messages sent
|
||||
debug mpls ldp zebra
|
||||
!
|
||||
mpls ldp
|
||||
router-id 10.0.255.6
|
||||
dual-stack transport-connection prefer ipv4
|
||||
!
|
||||
address-family ipv4
|
||||
label local allocate host-routes
|
||||
discovery targeted-hello accept
|
||||
discovery transport-address 10.0.255.6
|
||||
!
|
||||
interface eth-rt4
|
||||
interface eth-rt8
|
||||
!
|
||||
!
|
||||
address-family ipv6
|
||||
label local allocate host-routes
|
||||
discovery transport-address 2001:db8::6
|
||||
!
|
||||
interface eth-rt4
|
||||
interface eth-rt8
|
||||
!
|
||||
!
|
||||
!
|
22
tests/topotests/isis-rlfa-topo1/rt6/zebra.conf
Normal file
22
tests/topotests/isis-rlfa-topo1/rt6/zebra.conf
Normal file
@ -0,0 +1,22 @@
|
||||
log file zebra.log
|
||||
!
|
||||
hostname rt6
|
||||
!
|
||||
debug zebra kernel
|
||||
debug zebra packet
|
||||
debug zebra mpls
|
||||
!
|
||||
interface lo
|
||||
ip address 10.0.255.6/32
|
||||
ipv6 address 2001:db8::6/128
|
||||
!
|
||||
interface eth-rt4
|
||||
ip address 10.0.255.6/32
|
||||
!
|
||||
interface eth-rt8
|
||||
ip address 10.0.255.6/32
|
||||
!
|
||||
ip forwarding
|
||||
!
|
||||
line vty
|
||||
!
|
32
tests/topotests/isis-rlfa-topo1/rt7/isisd.conf
Normal file
32
tests/topotests/isis-rlfa-topo1/rt7/isisd.conf
Normal file
@ -0,0 +1,32 @@
|
||||
password 1
|
||||
hostname rt7
|
||||
log file isisd.log
|
||||
!
|
||||
debug isis events
|
||||
debug isis route-events
|
||||
debug isis spf-events
|
||||
debug isis lsp-gen
|
||||
!
|
||||
interface lo
|
||||
ip router isis 1
|
||||
ipv6 router isis 1
|
||||
isis passive
|
||||
!
|
||||
interface eth-rt5
|
||||
ip router isis 1
|
||||
ipv6 router isis 1
|
||||
isis hello-multiplier 3
|
||||
isis network point-to-point
|
||||
!
|
||||
interface eth-rt8
|
||||
ip router isis 1
|
||||
ipv6 router isis 1
|
||||
isis hello-multiplier 3
|
||||
isis network point-to-point
|
||||
!
|
||||
router isis 1
|
||||
net 49.0000.0000.0000.0007.00
|
||||
is-type level-1-2
|
||||
lsp-gen-interval 2
|
||||
topology ipv6-unicast
|
||||
!
|
30
tests/topotests/isis-rlfa-topo1/rt7/ldpd.conf
Normal file
30
tests/topotests/isis-rlfa-topo1/rt7/ldpd.conf
Normal file
@ -0,0 +1,30 @@
|
||||
log file ldpd.log
|
||||
!
|
||||
hostname rt7
|
||||
!
|
||||
debug mpls ldp messages recv
|
||||
debug mpls ldp messages sent
|
||||
debug mpls ldp zebra
|
||||
!
|
||||
mpls ldp
|
||||
router-id 10.0.255.7
|
||||
dual-stack transport-connection prefer ipv4
|
||||
!
|
||||
address-family ipv4
|
||||
label local allocate host-routes
|
||||
discovery targeted-hello accept
|
||||
discovery transport-address 10.0.255.7
|
||||
!
|
||||
interface eth-rt5
|
||||
interface eth-rt8
|
||||
!
|
||||
!
|
||||
address-family ipv6
|
||||
label local allocate host-routes
|
||||
discovery transport-address 2001:db8::7
|
||||
!
|
||||
interface eth-rt5
|
||||
interface eth-rt8
|
||||
!
|
||||
!
|
||||
!
|
22
tests/topotests/isis-rlfa-topo1/rt7/zebra.conf
Normal file
22
tests/topotests/isis-rlfa-topo1/rt7/zebra.conf
Normal file
@ -0,0 +1,22 @@
|
||||
log file zebra.log
|
||||
!
|
||||
hostname rt7
|
||||
!
|
||||
debug zebra kernel
|
||||
debug zebra packet
|
||||
debug zebra mpls
|
||||
!
|
||||
interface lo
|
||||
ip address 10.0.255.7/32
|
||||
ipv6 address 2001:db8::7/128
|
||||
!
|
||||
interface eth-rt5
|
||||
ip address 10.0.255.7/32
|
||||
!
|
||||
interface eth-rt8
|
||||
ip address 10.0.255.7/32
|
||||
!
|
||||
ip forwarding
|
||||
!
|
||||
line vty
|
||||
!
|
32
tests/topotests/isis-rlfa-topo1/rt8/isisd.conf
Normal file
32
tests/topotests/isis-rlfa-topo1/rt8/isisd.conf
Normal file
@ -0,0 +1,32 @@
|
||||
password 1
|
||||
hostname rt8
|
||||
log file isisd.log
|
||||
!
|
||||
debug isis events
|
||||
debug isis route-events
|
||||
debug isis spf-events
|
||||
debug isis lsp-gen
|
||||
!
|
||||
interface lo
|
||||
ip router isis 1
|
||||
ipv6 router isis 1
|
||||
isis passive
|
||||
!
|
||||
interface eth-rt6
|
||||
ip router isis 1
|
||||
ipv6 router isis 1
|
||||
isis hello-multiplier 3
|
||||
isis network point-to-point
|
||||
!
|
||||
interface eth-rt7
|
||||
ip router isis 1
|
||||
ipv6 router isis 1
|
||||
isis hello-multiplier 3
|
||||
isis network point-to-point
|
||||
!
|
||||
router isis 1
|
||||
net 49.0000.0000.0000.0008.00
|
||||
is-type level-1-2
|
||||
lsp-gen-interval 2
|
||||
topology ipv6-unicast
|
||||
!
|
30
tests/topotests/isis-rlfa-topo1/rt8/ldpd.conf
Normal file
30
tests/topotests/isis-rlfa-topo1/rt8/ldpd.conf
Normal file
@ -0,0 +1,30 @@
|
||||
log file ldpd.log
|
||||
!
|
||||
hostname rt8
|
||||
!
|
||||
debug mpls ldp messages recv
|
||||
debug mpls ldp messages sent
|
||||
debug mpls ldp zebra
|
||||
!
|
||||
mpls ldp
|
||||
router-id 10.0.255.8
|
||||
dual-stack transport-connection prefer ipv4
|
||||
!
|
||||
address-family ipv4
|
||||
label local allocate host-routes
|
||||
discovery targeted-hello accept
|
||||
discovery transport-address 10.0.255.8
|
||||
!
|
||||
interface eth-rt6
|
||||
interface eth-rt7
|
||||
!
|
||||
!
|
||||
address-family ipv6
|
||||
label local allocate host-routes
|
||||
discovery transport-address 2001:db8::8
|
||||
!
|
||||
interface eth-rt6
|
||||
interface eth-rt7
|
||||
!
|
||||
!
|
||||
!
|
22
tests/topotests/isis-rlfa-topo1/rt8/zebra.conf
Normal file
22
tests/topotests/isis-rlfa-topo1/rt8/zebra.conf
Normal file
@ -0,0 +1,22 @@
|
||||
log file zebra.log
|
||||
!
|
||||
hostname rt8
|
||||
!
|
||||
debug zebra kernel
|
||||
debug zebra packet
|
||||
debug zebra mpls
|
||||
!
|
||||
interface lo
|
||||
ip address 10.0.255.8/32
|
||||
ipv6 address 2001:db8::8/128
|
||||
!
|
||||
interface eth-rt6
|
||||
ip address 10.0.255.8/32
|
||||
!
|
||||
interface eth-rt7
|
||||
ip address 10.0.255.8/32
|
||||
!
|
||||
ip forwarding
|
||||
!
|
||||
line vty
|
||||
!
|
662
tests/topotests/isis-rlfa-topo1/test_isis_rlfa_topo1.py
Executable file
662
tests/topotests/isis-rlfa-topo1/test_isis_rlfa_topo1.py
Executable file
@ -0,0 +1,662 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
#
|
||||
# test_isis_rlfa_topo1.py
|
||||
# Part of NetDEF Topology Tests
|
||||
#
|
||||
# Copyright (c) 2020 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_rlfa_topo1.py:
|
||||
|
||||
+---------+ +---------+
|
||||
| | | |
|
||||
| RT1 | | RT2 |
|
||||
| +---------------------+ |
|
||||
| | | |
|
||||
+---+-----+ +------+--+
|
||||
| |
|
||||
| |
|
||||
| |
|
||||
+---+-----+ +------+--+
|
||||
| | | |
|
||||
| RT3 | | RT4 |
|
||||
| | | |
|
||||
| | | |
|
||||
+---+-----+ +------+--+
|
||||
| |
|
||||
| |
|
||||
| |
|
||||
+---+-----+ +------+--+
|
||||
| | | |
|
||||
| RT5 | | RT6 |
|
||||
| | | |
|
||||
| | | |
|
||||
+---+-----+ +------+--+
|
||||
| |
|
||||
| |
|
||||
| |
|
||||
+---+-----+ +------+--+
|
||||
| | | |
|
||||
| RT7 | | RT8 |
|
||||
| +---------------------+ |
|
||||
| | | |
|
||||
+---------+ +---------+
|
||||
"""
|
||||
|
||||
import os
|
||||
import sys
|
||||
import pytest
|
||||
import json
|
||||
import re
|
||||
import tempfile
|
||||
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
|
||||
|
||||
# Global multi-dimensional dictionary containing all expected outputs
|
||||
outputs = {}
|
||||
|
||||
|
||||
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", "rt7", "rt8"]:
|
||||
tgen.add_router(router)
|
||||
|
||||
#
|
||||
# Define connections
|
||||
#
|
||||
switch = tgen.add_switch("s1")
|
||||
switch.add_link(tgen.gears["rt1"], nodeif="eth-rt2")
|
||||
switch.add_link(tgen.gears["rt2"], nodeif="eth-rt1")
|
||||
switch = tgen.add_switch("s2")
|
||||
switch.add_link(tgen.gears["rt1"], nodeif="eth-rt3")
|
||||
switch.add_link(tgen.gears["rt3"], nodeif="eth-rt1")
|
||||
switch = tgen.add_switch("s3")
|
||||
switch.add_link(tgen.gears["rt2"], nodeif="eth-rt4")
|
||||
switch.add_link(tgen.gears["rt4"], nodeif="eth-rt2")
|
||||
switch = tgen.add_switch("s4")
|
||||
switch.add_link(tgen.gears["rt3"], nodeif="eth-rt5")
|
||||
switch.add_link(tgen.gears["rt5"], nodeif="eth-rt3")
|
||||
switch = tgen.add_switch("s5")
|
||||
switch.add_link(tgen.gears["rt4"], nodeif="eth-rt6")
|
||||
switch.add_link(tgen.gears["rt6"], nodeif="eth-rt4")
|
||||
switch = tgen.add_switch("s6")
|
||||
switch.add_link(tgen.gears["rt5"], nodeif="eth-rt7")
|
||||
switch.add_link(tgen.gears["rt7"], nodeif="eth-rt5")
|
||||
switch = tgen.add_switch("s7")
|
||||
switch.add_link(tgen.gears["rt6"], nodeif="eth-rt8")
|
||||
switch.add_link(tgen.gears["rt8"], nodeif="eth-rt6")
|
||||
switch = tgen.add_switch("s8")
|
||||
switch.add_link(tgen.gears["rt7"], nodeif="eth-rt8")
|
||||
switch.add_link(tgen.gears["rt8"], nodeif="eth-rt7")
|
||||
|
||||
#
|
||||
# Populate multi-dimensional dictionary containing all expected outputs
|
||||
#
|
||||
files = [
|
||||
"show_ip_route.ref",
|
||||
"show_ipv6_route.ref",
|
||||
"show_yang_interface_isis_adjacencies.ref",
|
||||
]
|
||||
for rname in ["rt1"]:
|
||||
outputs[rname] = {}
|
||||
for step in range(1, 10 + 1):
|
||||
outputs[rname][step] = {}
|
||||
for file in files:
|
||||
if step == 1:
|
||||
# Get snapshots relative to the expected initial network convergence
|
||||
filename = "{}/{}/step{}/{}".format(CWD, rname, step, file)
|
||||
outputs[rname][step][file] = open(filename).read()
|
||||
else:
|
||||
if file == "show_yang_interface_isis_adjacencies.ref":
|
||||
continue
|
||||
|
||||
# Get diff relative to the previous step
|
||||
filename = "{}/{}/step{}/{}.diff".format(CWD, rname, step, file)
|
||||
|
||||
# Create temporary files in order to apply the diff
|
||||
f_in = tempfile.NamedTemporaryFile()
|
||||
f_in.write(outputs[rname][step - 1][file])
|
||||
f_in.flush()
|
||||
f_out = tempfile.NamedTemporaryFile()
|
||||
os.system(
|
||||
"patch -s -o %s %s %s" % (f_out.name, f_in.name, filename)
|
||||
)
|
||||
|
||||
# Store the updated snapshot and remove the temporary files
|
||||
outputs[rname][step][file] = open(f_out.name).read()
|
||||
f_in.close()
|
||||
f_out.close()
|
||||
|
||||
|
||||
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_LDP, os.path.join(CWD, "{}/ldpd.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 router_compare_json_output(rname, command, reference):
|
||||
"Compare router JSON output"
|
||||
|
||||
logger.info('Comparing router "%s" "%s" output', rname, command)
|
||||
|
||||
tgen = get_topogen()
|
||||
expected = json.loads(reference)
|
||||
|
||||
# Run test function until we get an result. Wait at most 60 seconds.
|
||||
test_func = partial(topotest.router_json_cmp, tgen.gears[rname], command, expected)
|
||||
_, 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
|
||||
|
||||
|
||||
#
|
||||
# Step 1
|
||||
#
|
||||
# Test initial network convergence
|
||||
#
|
||||
def test_isis_adjacencies_step1():
|
||||
logger.info("Test (step 1): check IS-IS adjacencies")
|
||||
tgen = get_topogen()
|
||||
|
||||
# Skip if previous fatal error condition is raised
|
||||
if tgen.routers_have_failure():
|
||||
pytest.skip(tgen.errors)
|
||||
|
||||
for rname in ["rt1"]:
|
||||
router_compare_json_output(
|
||||
rname,
|
||||
"show yang operational-data /frr-interface:lib isisd",
|
||||
outputs[rname][1]["show_yang_interface_isis_adjacencies.ref"],
|
||||
)
|
||||
|
||||
|
||||
def test_rib_ipv4_step1():
|
||||
logger.info("Test (step 1): verify IPv4 RIB")
|
||||
tgen = get_topogen()
|
||||
|
||||
# Skip if previous fatal error condition is raised
|
||||
if tgen.routers_have_failure():
|
||||
pytest.skip(tgen.errors)
|
||||
|
||||
for rname in ["rt1"]:
|
||||
router_compare_json_output(
|
||||
rname, "show ip route isis json", outputs[rname][1]["show_ip_route.ref"]
|
||||
)
|
||||
|
||||
|
||||
def test_rib_ipv6_step1():
|
||||
logger.info("Test (step 1): verify IPv6 RIB")
|
||||
tgen = get_topogen()
|
||||
|
||||
# Skip if previous fatal error condition is raised
|
||||
if tgen.routers_have_failure():
|
||||
pytest.skip(tgen.errors)
|
||||
|
||||
for rname in ["rt1"]:
|
||||
router_compare_json_output(
|
||||
rname, "show ipv6 route isis json", outputs[rname][1]["show_ipv6_route.ref"]
|
||||
)
|
||||
|
||||
|
||||
#
|
||||
# Step 2
|
||||
#
|
||||
# Action(s):
|
||||
# -Configure rt8 (rt1's PQ router) to not accept targeted hello messages
|
||||
#
|
||||
# Expected changes:
|
||||
# -All rt1 backup routes should be uninstalled
|
||||
#
|
||||
def test_rib_ipv4_step2():
|
||||
logger.info("Test (step 2): verify IPv4 RIB")
|
||||
tgen = get_topogen()
|
||||
|
||||
# Skip if previous fatal error condition is raised
|
||||
if tgen.routers_have_failure():
|
||||
pytest.skip(tgen.errors)
|
||||
|
||||
logger.info("Configuring rt8 to not accept targeted hello messages")
|
||||
tgen.net["rt8"].cmd(
|
||||
'vtysh -c "conf t" -c "mpls ldp" -c "address-family ipv4" -c "no discovery targeted-hello accept"'
|
||||
)
|
||||
|
||||
for rname in ["rt1"]:
|
||||
router_compare_json_output(
|
||||
rname, "show ip route isis json", outputs[rname][2]["show_ip_route.ref"]
|
||||
)
|
||||
|
||||
|
||||
def test_rib_ipv6_step2():
|
||||
logger.info("Test (step 2): verify IPv6 RIB")
|
||||
tgen = get_topogen()
|
||||
|
||||
# Skip if previous fatal error condition is raised
|
||||
if tgen.routers_have_failure():
|
||||
pytest.skip(tgen.errors)
|
||||
|
||||
for rname in ["rt1"]:
|
||||
router_compare_json_output(
|
||||
rname, "show ipv6 route isis json", outputs[rname][2]["show_ipv6_route.ref"]
|
||||
)
|
||||
|
||||
|
||||
#
|
||||
# Step 3
|
||||
#
|
||||
# Action(s):
|
||||
# -Configure rt8 (rt1's PQ router) to accept targeted hello messages
|
||||
#
|
||||
# Expected changes:
|
||||
# -All rt1 previously uninstalled backup routes should be reinstalled
|
||||
#
|
||||
def test_rib_ipv4_step3():
|
||||
logger.info("Test (step 3): verify IPv4 RIB")
|
||||
tgen = get_topogen()
|
||||
|
||||
# Skip if previous fatal error condition is raised
|
||||
if tgen.routers_have_failure():
|
||||
pytest.skip(tgen.errors)
|
||||
|
||||
logger.info("Configuring rt8 to accept targeted hello messages")
|
||||
tgen.net["rt8"].cmd(
|
||||
'vtysh -c "conf t" -c "mpls ldp" -c "address-family ipv4" -c "discovery targeted-hello accept"'
|
||||
)
|
||||
|
||||
for rname in ["rt1"]:
|
||||
router_compare_json_output(
|
||||
rname, "show ip route isis json", outputs[rname][3]["show_ip_route.ref"]
|
||||
)
|
||||
|
||||
|
||||
def test_rib_ipv6_step3():
|
||||
logger.info("Test (step 3): verify IPv6 RIB")
|
||||
tgen = get_topogen()
|
||||
|
||||
# Skip if previous fatal error condition is raised
|
||||
if tgen.routers_have_failure():
|
||||
pytest.skip(tgen.errors)
|
||||
|
||||
for rname in ["rt1"]:
|
||||
router_compare_json_output(
|
||||
rname, "show ipv6 route isis json", outputs[rname][3]["show_ipv6_route.ref"]
|
||||
)
|
||||
|
||||
|
||||
#
|
||||
# Step 4
|
||||
#
|
||||
# Action(s):
|
||||
# -Disable RLFA on rt1's eth-rt2 interface
|
||||
#
|
||||
# Expected changes:
|
||||
# -All non-ECMP routes whose primary nexthop is eth-rt2 should lose their backup nexthops
|
||||
#
|
||||
def test_rib_ipv4_step4():
|
||||
logger.info("Test (step 4): verify IPv4 RIB")
|
||||
tgen = get_topogen()
|
||||
|
||||
# Skip if previous fatal error condition is raised
|
||||
if tgen.routers_have_failure():
|
||||
pytest.skip(tgen.errors)
|
||||
|
||||
logger.info("Disabling RLFA on rt1's eth-rt2 interface")
|
||||
tgen.net["rt1"].cmd(
|
||||
'vtysh -c "conf t" -c "interface eth-rt2" -c "no isis fast-reroute remote-lfa tunnel mpls-ldp"'
|
||||
)
|
||||
|
||||
for rname in ["rt1"]:
|
||||
router_compare_json_output(
|
||||
rname, "show ip route isis json", outputs[rname][4]["show_ip_route.ref"]
|
||||
)
|
||||
|
||||
|
||||
def test_rib_ipv6_step4():
|
||||
logger.info("Test (step 4): verify IPv6 RIB")
|
||||
tgen = get_topogen()
|
||||
|
||||
# Skip if previous fatal error condition is raised
|
||||
if tgen.routers_have_failure():
|
||||
pytest.skip(tgen.errors)
|
||||
|
||||
for rname in ["rt1"]:
|
||||
router_compare_json_output(
|
||||
rname, "show ipv6 route isis json", outputs[rname][4]["show_ipv6_route.ref"]
|
||||
)
|
||||
|
||||
|
||||
#
|
||||
# Step 5
|
||||
#
|
||||
# Action(s):
|
||||
# -Disable RLFA on rt1's eth-rt3 interface
|
||||
#
|
||||
# Expected changes:
|
||||
# -All non-ECMP routes whose primary nexthop is eth-rt3 should lose their backup nexthops
|
||||
#
|
||||
def test_rib_ipv4_step5():
|
||||
logger.info("Test (step 5): verify IPv4 RIB")
|
||||
tgen = get_topogen()
|
||||
|
||||
# Skip if previous fatal error condition is raised
|
||||
if tgen.routers_have_failure():
|
||||
pytest.skip(tgen.errors)
|
||||
|
||||
logger.info("Disabling RLFA on rt1's eth-rt3 interface")
|
||||
tgen.net["rt1"].cmd(
|
||||
'vtysh -c "conf t" -c "interface eth-rt3" -c "no isis fast-reroute remote-lfa tunnel mpls-ldp"'
|
||||
)
|
||||
|
||||
for rname in ["rt1"]:
|
||||
router_compare_json_output(
|
||||
rname, "show ip route isis json", outputs[rname][5]["show_ip_route.ref"]
|
||||
)
|
||||
|
||||
|
||||
def test_rib_ipv6_step5():
|
||||
logger.info("Test (step 5): verify IPv6 RIB")
|
||||
tgen = get_topogen()
|
||||
|
||||
# Skip if previous fatal error condition is raised
|
||||
if tgen.routers_have_failure():
|
||||
pytest.skip(tgen.errors)
|
||||
|
||||
for rname in ["rt1"]:
|
||||
router_compare_json_output(
|
||||
rname, "show ipv6 route isis json", outputs[rname][5]["show_ipv6_route.ref"]
|
||||
)
|
||||
|
||||
|
||||
#
|
||||
# Step 6
|
||||
#
|
||||
# Action(s):
|
||||
# -Re-enable RLFA on rt1's eth-rt2 and eth-rt3 interfaces
|
||||
#
|
||||
# Expected changes:
|
||||
# -Revert changes from the previous two steps (reinstall all backup routes)
|
||||
#
|
||||
def test_rib_ipv4_step6():
|
||||
logger.info("Test (step 6): verify IPv4 RIB")
|
||||
tgen = get_topogen()
|
||||
|
||||
# Skip if previous fatal error condition is raised
|
||||
if tgen.routers_have_failure():
|
||||
pytest.skip(tgen.errors)
|
||||
|
||||
logger.info("Re-enabling RLFA on rt1's eth-rt2 and eth-rt3 interfaces")
|
||||
tgen.net["rt1"].cmd(
|
||||
'vtysh -c "conf t" -c "interface eth-rt2" -c "isis fast-reroute remote-lfa tunnel mpls-ldp"'
|
||||
)
|
||||
tgen.net["rt1"].cmd(
|
||||
'vtysh -c "conf t" -c "interface eth-rt3" -c "isis fast-reroute remote-lfa tunnel mpls-ldp"'
|
||||
)
|
||||
|
||||
for rname in ["rt1"]:
|
||||
router_compare_json_output(
|
||||
rname, "show ip route isis json", outputs[rname][6]["show_ip_route.ref"]
|
||||
)
|
||||
|
||||
|
||||
def test_rib_ipv6_step6():
|
||||
logger.info("Test (step 6): verify IPv6 RIB")
|
||||
tgen = get_topogen()
|
||||
|
||||
# Skip if previous fatal error condition is raised
|
||||
if tgen.routers_have_failure():
|
||||
pytest.skip(tgen.errors)
|
||||
|
||||
for rname in ["rt1"]:
|
||||
router_compare_json_output(
|
||||
rname, "show ipv6 route isis json", outputs[rname][6]["show_ipv6_route.ref"]
|
||||
)
|
||||
|
||||
|
||||
#
|
||||
# Step 7
|
||||
#
|
||||
# Action(s):
|
||||
# -Configure a PQ node prefix-list filter
|
||||
#
|
||||
# Expected changes:
|
||||
# -All backup routes should be uninstalled
|
||||
#
|
||||
def test_rib_ipv4_step7():
|
||||
logger.info("Test (step 7): verify IPv4 RIB")
|
||||
tgen = get_topogen()
|
||||
|
||||
# Skip if previous fatal error condition is raised
|
||||
if tgen.routers_have_failure():
|
||||
pytest.skip(tgen.errors)
|
||||
|
||||
logger.info("Configuring a PQ node prefix-list filter")
|
||||
tgen.net["rt1"].cmd(
|
||||
'vtysh -c "conf t" -c "router isis 1" -c "fast-reroute remote-lfa prefix-list PLIST"'
|
||||
)
|
||||
|
||||
for rname in ["rt1"]:
|
||||
router_compare_json_output(
|
||||
rname, "show ip route isis json", outputs[rname][7]["show_ip_route.ref"]
|
||||
)
|
||||
|
||||
|
||||
def test_rib_ipv6_step7():
|
||||
logger.info("Test (step 7): verify IPv6 RIB")
|
||||
tgen = get_topogen()
|
||||
|
||||
# Skip if previous fatal error condition is raised
|
||||
if tgen.routers_have_failure():
|
||||
pytest.skip(tgen.errors)
|
||||
|
||||
for rname in ["rt1"]:
|
||||
router_compare_json_output(
|
||||
rname, "show ipv6 route isis json", outputs[rname][7]["show_ipv6_route.ref"]
|
||||
)
|
||||
|
||||
|
||||
#
|
||||
# Step 8
|
||||
#
|
||||
# Action(s):
|
||||
# -Configure a prefix-list allowing rt8 as a PQ node
|
||||
#
|
||||
# Expected changes:
|
||||
# -All backup routes should be installed again
|
||||
#
|
||||
def test_rib_ipv4_step8():
|
||||
logger.info("Test (step 8): verify IPv4 RIB")
|
||||
tgen = get_topogen()
|
||||
|
||||
# Skip if previous fatal error condition is raised
|
||||
if tgen.routers_have_failure():
|
||||
pytest.skip(tgen.errors)
|
||||
|
||||
logger.info("Configuring a prefix-list allowing rt8 as a PQ node")
|
||||
tgen.net["rt1"].cmd(
|
||||
'vtysh -c "conf t" -c "ip prefix-list PLIST seq 5 permit 10.0.255.8/32"'
|
||||
)
|
||||
|
||||
for rname in ["rt1"]:
|
||||
router_compare_json_output(
|
||||
rname, "show ip route isis json", outputs[rname][8]["show_ip_route.ref"]
|
||||
)
|
||||
|
||||
|
||||
def test_rib_ipv6_step8():
|
||||
logger.info("Test (step 8): verify IPv6 RIB")
|
||||
tgen = get_topogen()
|
||||
|
||||
# Skip if previous fatal error condition is raised
|
||||
if tgen.routers_have_failure():
|
||||
pytest.skip(tgen.errors)
|
||||
|
||||
for rname in ["rt1"]:
|
||||
router_compare_json_output(
|
||||
rname, "show ipv6 route isis json", outputs[rname][8]["show_ipv6_route.ref"]
|
||||
)
|
||||
|
||||
|
||||
#
|
||||
# Step 9
|
||||
#
|
||||
# Action(s):
|
||||
# -Change the maximum metric up to the PQ node to 30 on the eth-rt2 interface
|
||||
#
|
||||
# Expected changes:
|
||||
# -All non-ECMP routes whose primary nexthop is eth-rt2 should lose their backup nexthops
|
||||
#
|
||||
def test_rib_ipv4_step9():
|
||||
logger.info("Test (step 9): verify IPv4 RIB")
|
||||
tgen = get_topogen()
|
||||
|
||||
# Skip if previous fatal error condition is raised
|
||||
if tgen.routers_have_failure():
|
||||
pytest.skip(tgen.errors)
|
||||
|
||||
logger.info(
|
||||
"Changing the maximum metric up to the PQ node to 30 on the eth-rt2 interface"
|
||||
)
|
||||
tgen.net["rt1"].cmd(
|
||||
'vtysh -c "conf t" -c "interface eth-rt2" -c "isis fast-reroute remote-lfa maximum-metric 30"'
|
||||
)
|
||||
|
||||
for rname in ["rt1"]:
|
||||
router_compare_json_output(
|
||||
rname, "show ip route isis json", outputs[rname][9]["show_ip_route.ref"]
|
||||
)
|
||||
|
||||
|
||||
def test_rib_ipv6_step9():
|
||||
logger.info("Test (step 9): verify IPv6 RIB")
|
||||
tgen = get_topogen()
|
||||
|
||||
# Skip if previous fatal error condition is raised
|
||||
if tgen.routers_have_failure():
|
||||
pytest.skip(tgen.errors)
|
||||
|
||||
for rname in ["rt1"]:
|
||||
router_compare_json_output(
|
||||
rname, "show ipv6 route isis json", outputs[rname][9]["show_ipv6_route.ref"]
|
||||
)
|
||||
|
||||
|
||||
#
|
||||
# Step 10
|
||||
#
|
||||
# Action(s):
|
||||
# -Change the maximum metric up to the PQ node to 40 on the eth-rt2 interface
|
||||
#
|
||||
# Expected changes:
|
||||
# -All non-ECMP routes whose primary nexthop is eth-rt2 should recover their backup nexthops
|
||||
#
|
||||
def test_rib_ipv4_step10():
|
||||
logger.info("Test (step 10): verify IPv4 RIB")
|
||||
tgen = get_topogen()
|
||||
|
||||
# Skip if previous fatal error condition is raised
|
||||
if tgen.routers_have_failure():
|
||||
pytest.skip(tgen.errors)
|
||||
|
||||
logger.info(
|
||||
"Changing the maximum metric up to the PQ node to 40 on the eth-rt2 interface"
|
||||
)
|
||||
tgen.net["rt1"].cmd(
|
||||
'vtysh -c "conf t" -c "interface eth-rt2" -c "isis fast-reroute remote-lfa maximum-metric 40"'
|
||||
)
|
||||
|
||||
for rname in ["rt1"]:
|
||||
router_compare_json_output(
|
||||
rname, "show ip route isis json", outputs[rname][10]["show_ip_route.ref"]
|
||||
)
|
||||
|
||||
|
||||
def test_rib_ipv6_step10():
|
||||
logger.info("Test (step 10): verify IPv6 RIB")
|
||||
tgen = get_topogen()
|
||||
|
||||
# Skip if previous fatal error condition is raised
|
||||
if tgen.routers_have_failure():
|
||||
pytest.skip(tgen.errors)
|
||||
|
||||
for rname in ["rt1"]:
|
||||
router_compare_json_output(
|
||||
rname,
|
||||
"show ipv6 route isis json",
|
||||
outputs[rname][10]["show_ipv6_route.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))
|
@ -248,6 +248,10 @@ module frr-isisd {
|
||||
type string;
|
||||
}
|
||||
|
||||
typedef prefix-list-ref {
|
||||
type string;
|
||||
}
|
||||
|
||||
grouping redistribute-attributes {
|
||||
description
|
||||
"Common optional attributes of any redistribute entry.";
|
||||
@ -410,6 +414,19 @@ module frr-isisd {
|
||||
}
|
||||
}
|
||||
|
||||
grouping global-config-remote-lfa {
|
||||
container remote-lfa {
|
||||
description
|
||||
"Remote LFA configuration.";
|
||||
|
||||
leaf prefix-list {
|
||||
type prefix-list-ref;
|
||||
description
|
||||
"Filter PQ node router ID based on prefix list.";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
grouping interface-config-lfa {
|
||||
container lfa {
|
||||
description
|
||||
@ -428,6 +445,32 @@ module frr-isisd {
|
||||
}
|
||||
}
|
||||
|
||||
grouping interface-config-remote-lfa {
|
||||
container remote-lfa {
|
||||
description
|
||||
"Remote LFA configuration.";
|
||||
|
||||
leaf enable {
|
||||
type boolean;
|
||||
default false;
|
||||
description
|
||||
"Enables remote LFA computation using LDP tunnels.";
|
||||
must ". = 'false' or ../../lfa/enable = 'true'" {
|
||||
error-message
|
||||
"Remote LFA depends on classic LFA being configured in the interface.";
|
||||
}
|
||||
|
||||
}
|
||||
leaf maximum-metric {
|
||||
type uint32 {
|
||||
range "1..16777215";
|
||||
}
|
||||
description
|
||||
"Limit remote LFA node selection within the metric.";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
grouping interface-config-ti-lfa {
|
||||
container ti-lfa {
|
||||
description
|
||||
@ -761,6 +804,7 @@ module frr-isisd {
|
||||
"Can't enable both classic LFA and TI-LFA in the same interface.";
|
||||
}
|
||||
uses interface-config-lfa;
|
||||
uses interface-config-remote-lfa;
|
||||
uses interface-config-ti-lfa;
|
||||
}
|
||||
container level-2 {
|
||||
@ -771,6 +815,7 @@ module frr-isisd {
|
||||
"Can't enable both classic LFA and TI-LFA in the same interface.";
|
||||
}
|
||||
uses interface-config-lfa;
|
||||
uses interface-config-remote-lfa;
|
||||
uses interface-config-ti-lfa;
|
||||
}
|
||||
}
|
||||
@ -1394,11 +1439,13 @@ module frr-isisd {
|
||||
description
|
||||
"Level-1 IP Fast-reroute configuration.";
|
||||
uses global-config-lfa;
|
||||
uses global-config-remote-lfa;
|
||||
}
|
||||
container level-2 {
|
||||
description
|
||||
"Level-2 IP Fast-reroute configuration.";
|
||||
uses global-config-lfa;
|
||||
uses global-config-remote-lfa;
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user