diff options
author | Donald Sharp <sharpd@cumulusnetworks.com> | 2020-12-03 02:43:51 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2020-12-03 02:43:51 +0100 |
commit | cb5a294642575f8c0789631226c7afa70040be78 (patch) | |
tree | c09c95dffd8b6c6a74f9dc07ad6909aa4775c6ae | |
parent | Merge pull request #7657 from mjstapp/fix_topo_asan_noise (diff) | |
parent | tests: add IS-IS classic LFA topotest (diff) | |
download | frr-cb5a294642575f8c0789631226c7afa70040be78.tar.xz frr-cb5a294642575f8c0789631226c7afa70040be78.zip |
Merge pull request #7590 from opensourcerouting/isisd-lfa
isisd: add support for classic LFA
69 files changed, 7844 insertions, 247 deletions
diff --git a/doc/user/isisd.rst b/doc/user/isisd.rst index 81333a216..f991e3f07 100644 --- a/doc/user/isisd.rst +++ b/doc/user/isisd.rst @@ -175,6 +175,35 @@ ISIS Timer Set minimum interval between consecutive SPF calculations in seconds. +.. _isis-fast-reroute: + +ISIS Fast-Reroute +================= + +.. index:: spf prefix-priority [critical | high | medium] WORD +.. clicmd:: spf prefix-priority [critical | high | medium] WORD + +.. index:: spf prefix-priority [critical | high | medium] WORD +.. clicmd:: no spf prefix-priority [critical | high | medium] [WORD] + + Assign a priority to the prefixes that match the specified access-list. + +.. index:: fast-reroute priority-limit [critical | high | medium] [level-1 | level-2] +.. clicmd:: [no] fast-reroute priority-limit [critical | high | medium] [level-1 | level-2] + + Limit LFA backup computation up to the specified prefix priority. + +.. index:: fast-reroute lfa tiebreaker [downstream | lowest-backup-metric | node-protecting] index (1-255) [level-1 | level-2] +.. clicmd:: [no] fast-reroute lfa tiebreaker [downstream | lowest-backup-metric | node-protecting] index (1-255) [level-1 | level-2] + + Configure a tie-breaker for multiple LFA backups. Lower indexes are processed + first. + +.. index:: fast-reroute load-sharing disable [level-1 | level-2] +.. clicmd:: [no] fast-reroute load-sharing disable [level-1 | level-2] + + Disable load sharing across multiple LFA backups. + .. _isis-region: ISIS region @@ -356,6 +385,16 @@ ISIS interface Enable or disable :rfc:`5303` Three-Way Handshake for P2P adjacencies. Three-Way Handshake is enabled by default. +.. index:: isis fast-reroute lfa [level-1 | level-2] +.. clicmd:: [no] isis fast-reroute lfa [level-1 | level-2] + + Enable per-prefix LFA fast reroute link protection. + +.. index:: isis fast-reroute lfa [level-1 | level-2] exclude interface IFNAME +.. clicmd:: [no] isis fast-reroute lfa [level-1 | level-2] exclude interface IFNAME + + Exclude an interface from the LFA backup nexthop computation. + .. index:: isis fast-reroute ti-lfa [level-1|level-2] [node-protection] .. clicmd:: [no] isis fast-reroute ti-lfa [level-1|level-2] [node-protection] @@ -430,6 +469,12 @@ Showing ISIS information Show the ISIS routing table, as determined by the most recent SPF calculation. +.. index:: show isis fast-reroute summary [level-1|level-2] +.. clicmd:: show isis fast-reroute summary [level-1|level-2] + + Show information about the number of prefixes having LFA protection, + and network-wide LFA coverage. + .. _isis-traffic-engineering: Traffic Engineering @@ -641,13 +686,13 @@ Debugging ISIS IS-IS Segment Routing events. -.. index:: debug isis ti-lfa -.. clicmd:: debug isis ti-lfa +.. index:: debug isis lfa +.. clicmd:: debug isis lfa -.. index:: debug isis ti-lfa -.. clicmd:: no debug isis ti-lfa +.. index:: debug isis lfa +.. clicmd:: no debug isis lfa - IS-IS TI-LFA events. + IS-IS LFA events. .. index:: show debugging isis .. clicmd:: show debugging isis diff --git a/isisd/isis_circuit.c b/isisd/isis_circuit.c index e3c70264f..2580a7c43 100644 --- a/isisd/isis_circuit.c +++ b/isisd/isis_circuit.c @@ -140,6 +140,8 @@ struct isis_circuit *isis_circuit_new(struct isis *isis) #endif /* ifndef FABRICD */ circuit_mt_init(circuit); + isis_lfa_excluded_ifaces_init(circuit, ISIS_LEVEL1); + isis_lfa_excluded_ifaces_init(circuit, ISIS_LEVEL2); QOBJ_REG(circuit, isis_circuit); @@ -156,6 +158,8 @@ void isis_circuit_del(struct isis_circuit *circuit) isis_circuit_if_unbind(circuit, circuit->interface); circuit_mt_finish(circuit); + isis_lfa_excluded_ifaces_clear(circuit, ISIS_LEVEL1); + isis_lfa_excluded_ifaces_clear(circuit, ISIS_LEVEL2); /* and lastly the circuit itself */ XFREE(MTYPE_ISIS_CIRCUIT, circuit); diff --git a/isisd/isis_circuit.h b/isisd/isis_circuit.h index b4b03bf6b..e736d8fb1 100644 --- a/isisd/isis_circuit.h +++ b/isisd/isis_circuit.h @@ -141,6 +141,8 @@ struct isis_circuit { bool disable_threeway_adj; struct bfd_info *bfd_info; struct ldp_sync_info *ldp_sync_info; + bool lfa_protection[ISIS_LEVELS]; + struct hash *lfa_excluded_ifaces[ISIS_LEVELS]; bool tilfa_protection[ISIS_LEVELS]; bool tilfa_node_protection[ISIS_LEVELS]; /* diff --git a/isisd/isis_cli.c b/isisd/isis_cli.c index 6c6d88ad5..1f0bebaf4 100644 --- a/isisd/isis_cli.c +++ b/isisd/isis_cli.c @@ -1137,6 +1137,54 @@ void cli_show_isis_spf_ietf_backoff(struct vty *vty, struct lyd_node *dnode, } /* + * XPath: /frr-isisd:isis/instance/spf/prefix-priorities/medium/access-list-name + */ +DEFPY_YANG(spf_prefix_priority, spf_prefix_priority_cmd, + "spf prefix-priority <critical|high|medium>$priority WORD$acl_name", + "SPF configuration\n" + "Configure a prefix priority list\n" + "Specify critical priority prefixes\n" + "Specify high priority prefixes\n" + "Specify medium priority prefixes\n" + "Access-list name\n") +{ + char xpath[XPATH_MAXLEN]; + + snprintf(xpath, XPATH_MAXLEN, + "./spf/prefix-priorities/%s/access-list-name", priority); + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, acl_name); + + return nb_cli_apply_changes(vty, NULL); +} + +DEFPY_YANG(no_spf_prefix_priority, no_spf_prefix_priority_cmd, + "no spf prefix-priority <critical|high|medium>$priority [WORD]", + NO_STR + "SPF configuration\n" + "Configure a prefix priority list\n" + "Specify critical priority prefixes\n" + "Specify high priority prefixes\n" + "Specify medium priority prefixes\n" + "Access-list name\n") +{ + char xpath[XPATH_MAXLEN]; + + snprintf(xpath, XPATH_MAXLEN, + "./spf/prefix-priorities/%s/access-list-name", priority); + nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL); + + return nb_cli_apply_changes(vty, NULL); +} + +void cli_show_isis_spf_prefix_priority(struct vty *vty, struct lyd_node *dnode, + bool show_defaults) +{ + vty_out(vty, " spf prefix-priority %s %s\n", + dnode->parent->schema->name, + yang_dnode_get_string(dnode, NULL)); +} + +/* * XPath: /frr-isisd:isis/instance/purge-originator */ DEFPY_YANG(area_purge_originator, area_purge_originator_cmd, "[no] purge-originator", @@ -1729,6 +1777,176 @@ void cli_show_isis_prefix_sid(struct vty *vty, struct lyd_node *dnode, vty_out(vty, "\n"); } + +/* + * XPath: /frr-isisd:isis/instance/fast-reroute/level-{1,2}/lfa/priority-limit + */ +DEFPY_YANG (isis_frr_lfa_priority_limit, + isis_frr_lfa_priority_limit_cmd, + "[no] fast-reroute priority-limit <critical|high|medium>$priority [<level-1|level-2>$level]", + NO_STR + "Configure Fast ReRoute\n" + "Limit backup computation up to the prefix priority\n" + "Compute for critical priority prefixes only\n" + "Compute for critical & high priority prefixes\n" + "Compute for critical, high & medium priority prefixes\n" + "Set priority-limit for level-1 only\n" + "Set priority-limit for level-2 only\n") +{ + if (!level || strmatch(level, "level-1")) { + if (no) { + nb_cli_enqueue_change( + vty, + "./fast-reroute/level-1/lfa/priority-limit", + NB_OP_DESTROY, NULL); + } else { + nb_cli_enqueue_change( + vty, + "./fast-reroute/level-1/lfa/priority-limit", + NB_OP_CREATE, priority); + } + } + if (!level || strmatch(level, "level-2")) { + if (no) { + nb_cli_enqueue_change( + vty, + "./fast-reroute/level-2/lfa/priority-limit", + NB_OP_DESTROY, NULL); + } else { + nb_cli_enqueue_change( + vty, + "./fast-reroute/level-2/lfa/priority-limit", + NB_OP_CREATE, priority); + } + } + + return nb_cli_apply_changes(vty, NULL); +} + +void cli_show_isis_frr_lfa_priority_limit(struct vty *vty, + struct lyd_node *dnode, + bool show_defaults) +{ + vty_out(vty, " fast-reroute priority-limit %s %s\n", + yang_dnode_get_string(dnode, NULL), + dnode->parent->parent->schema->name); +} + +/* + * XPath: /frr-isisd:isis/instance/fast-reroute/level-{1,2}/lfa/tiebreaker + */ +DEFPY_YANG (isis_frr_lfa_tiebreaker, + isis_frr_lfa_tiebreaker_cmd, + "[no] fast-reroute lfa\ + tiebreaker <downstream|lowest-backup-metric|node-protecting>$type\ + index (1-255)$index\ + [<level-1|level-2>$level]", + NO_STR + "Configure Fast ReRoute\n" + "LFA configuration\n" + "Configure tiebreaker for multiple backups\n" + "Prefer backup path via downstream node\n" + "Prefer backup path with lowest total metric\n" + "Prefer node protecting backup path\n" + "Set preference order among tiebreakers\n" + "Index\n" + "Configure tiebreaker for level-1 only\n" + "Configure tiebreaker for level-2 only\n") +{ + char xpath[XPATH_MAXLEN]; + + if (!level || strmatch(level, "level-1")) { + if (no) { + snprintf( + xpath, XPATH_MAXLEN, + "./fast-reroute/level-1/lfa/tiebreaker[index='%s']", + index_str); + nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL); + } else { + snprintf( + xpath, XPATH_MAXLEN, + "./fast-reroute/level-1/lfa/tiebreaker[index='%s']/type", + index_str); + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, type); + } + } + if (!level || strmatch(level, "level-2")) { + if (no) { + snprintf( + xpath, XPATH_MAXLEN, + "./fast-reroute/level-2/lfa/tiebreaker[index='%s']", + index_str); + nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL); + } else { + snprintf( + xpath, XPATH_MAXLEN, + "./fast-reroute/level-2/lfa/tiebreaker[index='%s']/type", + index_str); + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, type); + } + } + + return nb_cli_apply_changes(vty, NULL); +} + +void cli_show_isis_frr_lfa_tiebreaker(struct vty *vty, struct lyd_node *dnode, + bool show_defaults) +{ + vty_out(vty, " fast-reroute lfa tiebreaker %s index %s %s\n", + yang_dnode_get_string(dnode, "./type"), + yang_dnode_get_string(dnode, "./index"), + dnode->parent->parent->schema->name); +} + +/* + * XPath: /frr-isisd:isis/instance/fast-reroute/level-{1,2}/lfa/load-sharing + */ +DEFPY_YANG (isis_frr_lfa_load_sharing, + isis_frr_lfa_load_sharing_cmd, + "[no] fast-reroute load-sharing disable [<level-1|level-2>$level]", + NO_STR + "Configure Fast ReRoute\n" + "Load share prefixes across multiple backups\n" + "Disable load sharing\n" + "Disable load sharing for level-1 only\n" + "Disable load sharing for level-2 only\n") +{ + if (!level || strmatch(level, "level-1")) { + if (no) { + nb_cli_enqueue_change( + vty, "./fast-reroute/level-1/lfa/load-sharing", + NB_OP_DESTROY, "true"); + } else { + nb_cli_enqueue_change( + vty, "./fast-reroute/level-1/lfa/load-sharing", + NB_OP_CREATE, "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"); + } else { + nb_cli_enqueue_change( + vty, "./fast-reroute/level-2/lfa/load-sharing", + NB_OP_CREATE, "false"); + } + } + + return nb_cli_apply_changes(vty, NULL); +} + +void cli_show_isis_frr_lfa_load_sharing(struct vty *vty, struct lyd_node *dnode, + bool show_defaults) +{ + if (!yang_dnode_get_bool(dnode, NULL)) + vty_out(vty, " no"); + + vty_out(vty, " fast-reroute load-sharing disable %s\n", + dnode->parent->parent->schema->name); +} + /* * XPath: /frr-interface:lib/interface/frr-isisd:isis/passive */ @@ -2386,7 +2604,164 @@ void cli_show_ip_isis_priority(struct vty *vty, struct lyd_node *dnode, } /* - * XPath: /frr-interface:lib/interface/frr-isisd:isis/fast-reroute/ti-lfa/enable + * XPath: /frr-interface:lib/interface/frr-isisd:isis/fast-reroute + */ +void cli_show_ip_isis_frr(struct vty *vty, struct lyd_node *dnode, + bool show_defaults) +{ + bool l1_enabled, l2_enabled; + bool l1_node_protection, l2_node_protection; + + /* Classic LFA */ + l1_enabled = yang_dnode_get_bool(dnode, "./level-1/lfa/enable"); + l2_enabled = yang_dnode_get_bool(dnode, "./level-2/lfa/enable"); + + if (l1_enabled || l2_enabled) { + if (l1_enabled == l2_enabled) { + vty_out(vty, " isis fast-reroute lfa\n"); + vty_out(vty, "\n"); + } else { + if (l1_enabled) + vty_out(vty, + " isis fast-reroute lfa level-1\n"); + if (l2_enabled) + vty_out(vty, + " isis fast-reroute lfa 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"); + l1_node_protection = + yang_dnode_get_bool(dnode, "./level-1/ti-lfa/node-protection"); + l2_node_protection = + yang_dnode_get_bool(dnode, "./level-2/ti-lfa/node-protection"); + + if (l1_enabled || l2_enabled) { + if (l1_enabled == l2_enabled + && l1_node_protection == l2_node_protection) { + vty_out(vty, " isis fast-reroute ti-lfa"); + if (l1_node_protection) + vty_out(vty, " node-protection"); + vty_out(vty, "\n"); + } else { + if (l1_enabled) { + vty_out(vty, + " isis fast-reroute ti-lfa level-1"); + if (l1_node_protection) + vty_out(vty, " node-protection"); + vty_out(vty, "\n"); + } + if (l2_enabled) { + vty_out(vty, + " isis fast-reroute ti-lfa level-2"); + if (l2_node_protection) + vty_out(vty, " node-protection"); + vty_out(vty, "\n"); + } + } + } +} + +/* + * XPath: /frr-interface:lib/interface/frr-isisd:isis/fast-reroute/level-{1,2}/lfa/enable + */ +DEFPY(isis_lfa, isis_lfa_cmd, + "[no] isis fast-reroute lfa [level-1|level-2]$level", + NO_STR + "IS-IS routing protocol\n" + "Interface IP Fast-reroute configuration\n" + "Enable LFA computation\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/lfa/enable", + NB_OP_MODIFY, "false"); + } else { + nb_cli_enqueue_change( + vty, + "./frr-isisd:isis/fast-reroute/level-1/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/lfa/enable", + NB_OP_MODIFY, "false"); + } else { + nb_cli_enqueue_change( + vty, + "./frr-isisd:isis/fast-reroute/level-2/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}/lfa/exclude-interface + */ +DEFPY(isis_lfa_exclude_interface, isis_lfa_exclude_interface_cmd, + "[no] isis fast-reroute lfa [level-1|level-2]$level exclude interface IFNAME$ifname", + NO_STR + "IS-IS routing protocol\n" + "Interface IP Fast-reroute configuration\n" + "Enable LFA computation\n" + "Enable LFA computation for Level 1 only\n" + "Enable LFA computation for Level 2 only\n" + "FRR exclusion information\n" + "Exclude an interface from computation\n" + "Interface name\n") +{ + if (!level || strmatch(level, "level-1")) { + if (no) { + nb_cli_enqueue_change( + vty, + "./frr-isisd:isis/fast-reroute/level-1/lfa/exclude-interface", + NB_OP_DESTROY, ifname); + } else { + nb_cli_enqueue_change( + vty, + "./frr-isisd:isis/fast-reroute/level-1/lfa/exclude-interface", + NB_OP_CREATE, ifname); + } + } + if (!level || strmatch(level, "level-2")) { + if (no) { + nb_cli_enqueue_change( + vty, + "./frr-isisd:isis/fast-reroute/level-2/lfa/exclude-interface", + NB_OP_DESTROY, ifname); + } else { + nb_cli_enqueue_change( + vty, + "./frr-isisd:isis/fast-reroute/level-2/lfa/exclude-interface", + NB_OP_CREATE, ifname); + } + } + + return nb_cli_apply_changes(vty, NULL); +} + +void cli_show_frr_lfa_exclude_interface(struct vty *vty, struct lyd_node *dnode, + bool show_defaults) +{ + vty_out(vty, " isis fast-reroute lfa %s exclude interface %s\n", + dnode->parent->parent->schema->name, + yang_dnode_get_string(dnode, NULL)); +} + +/* + * XPath: /frr-interface:lib/interface/frr-isisd:isis/fast-reroute/level-{1,2}/ti-lfa/enable */ DEFPY(isis_ti_lfa, isis_ti_lfa_cmd, "[no] isis fast-reroute ti-lfa [level-1|level-2]$level [node-protection$node_protection]", @@ -2446,41 +2821,6 @@ DEFPY(isis_ti_lfa, isis_ti_lfa_cmd, return nb_cli_apply_changes(vty, NULL); } -void cli_show_ip_isis_ti_lfa(struct vty *vty, struct lyd_node *dnode, - bool show_defaults) -{ - bool l1_enabled, l2_enabled; - bool l1_node_protection, l2_node_protection; - - l1_enabled = yang_dnode_get_bool(dnode, "./level-1/ti-lfa/enable"); - l2_enabled = yang_dnode_get_bool(dnode, "./level-2/ti-lfa/enable"); - l1_node_protection = - yang_dnode_get_bool(dnode, "./level-1/ti-lfa/node-protection"); - l2_node_protection = - yang_dnode_get_bool(dnode, "./level-2/ti-lfa/node-protection"); - - if (l1_enabled == l2_enabled - && l1_node_protection == l2_node_protection) { - vty_out(vty, " isis fast-reroute ti-lfa"); - if (l1_node_protection) - vty_out(vty, " node-protection"); - vty_out(vty, "\n"); - } else { - if (l1_enabled) { - vty_out(vty, " isis fast-reroute ti-lfa level-1"); - if (l1_node_protection) - vty_out(vty, " node-protection"); - vty_out(vty, "\n"); - } - if (l2_enabled) { - vty_out(vty, " isis fast-reroute ti-lfa level-2"); - if (l2_node_protection) - vty_out(vty, " node-protection"); - vty_out(vty, "\n"); - } - } -} - /* * XPath: /frr-isisd:isis/instance/log-adjacency-changes */ @@ -2714,6 +3054,8 @@ void isis_cli_init(void) install_element(ISIS_NODE, &spf_interval_cmd); install_element(ISIS_NODE, &no_spf_interval_cmd); + install_element(ISIS_NODE, &spf_prefix_priority_cmd); + install_element(ISIS_NODE, &no_spf_prefix_priority_cmd); install_element(ISIS_NODE, &spf_delay_ietf_cmd); install_element(ISIS_NODE, &no_spf_delay_ietf_cmd); @@ -2740,6 +3082,9 @@ void isis_cli_init(void) install_element(ISIS_NODE, &no_isis_sr_node_msd_cmd); install_element(ISIS_NODE, &isis_sr_prefix_sid_cmd); install_element(ISIS_NODE, &no_isis_sr_prefix_sid_cmd); + 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(INTERFACE_NODE, &isis_passive_cmd); @@ -2775,6 +3120,8 @@ void isis_cli_init(void) install_element(INTERFACE_NODE, &isis_priority_cmd); install_element(INTERFACE_NODE, &no_isis_priority_cmd); + install_element(INTERFACE_NODE, &isis_lfa_cmd); + install_element(INTERFACE_NODE, &isis_lfa_exclude_interface_cmd); install_element(INTERFACE_NODE, &isis_ti_lfa_cmd); install_element(ISIS_NODE, &log_adj_changes_cmd); diff --git a/isisd/isis_ldp_sync.c b/isisd/isis_ldp_sync.c index 988af64c4..3b1faffe5 100644 --- a/isisd/isis_ldp_sync.c +++ b/isisd/isis_ldp_sync.c @@ -429,20 +429,24 @@ void isis_ldp_sync_set_if_metric(struct isis_circuit *circuit, bool run_regen) if (circuit->area->newmetric) { ldp_sync_info->metric[0] = circuit->te_metric[0]; - circuit->te_metric[0] = LDP_ISIS_LSINFINITY; + circuit->te_metric[0] = + ISIS_WIDE_METRIC_INFINITY; } else { ldp_sync_info->metric[0] = circuit->metric[0]; - circuit->metric[0] = LDP_ISIS_LSINFINITY_NL; + circuit->metric[0] = + ISIS_NARROW_METRIC_INFINITY; } } if (circuit->is_type & IS_LEVEL_2) { if (circuit->area->newmetric) { ldp_sync_info->metric[1] = circuit->te_metric[1]; - circuit->te_metric[1] = LDP_ISIS_LSINFINITY; + circuit->te_metric[1] = + ISIS_WIDE_METRIC_INFINITY; } else { ldp_sync_info->metric[1] = circuit->metric[1]; - circuit->metric[1] = LDP_ISIS_LSINFINITY_NL; + circuit->metric[1] = + ISIS_NARROW_METRIC_INFINITY; } } } else { diff --git a/isisd/isis_ldp_sync.h b/isisd/isis_ldp_sync.h index 6017cdf00..61ac94607 100644 --- a/isisd/isis_ldp_sync.h +++ b/isisd/isis_ldp_sync.h @@ -20,9 +20,6 @@ #ifndef _ZEBRA_ISIS_LDP_SYNC_H #define _ZEBRA_ISIS_LDP_SYNC_H -#define LDP_ISIS_LSINFINITY 0xFFFFFE /* wide link metric */ -#define LDP_ISIS_LSINFINITY_NL 62 /* narrow link metric */ - /* Macro to log debug message */ #define ils_debug(...) \ do { \ diff --git a/isisd/isis_lfa.c b/isisd/isis_lfa.c index f22e4a708..fc6b435b6 100644 --- a/isisd/isis_lfa.c +++ b/isisd/isis_lfa.c @@ -40,6 +40,8 @@ #include "isisd/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"); static inline int isis_spf_node_compare(const struct isis_spf_node *a, const struct isis_spf_node *b) @@ -120,6 +122,185 @@ struct isis_spf_node *isis_spf_node_find(const struct isis_spf_nodes *nodes, } /** + * LFA tiebreaker RB-tree comparison function. + * + * @param a First LFA tiebreaker + * @param b Second LFA tiebreaker + * + * @return -1 (a < b), 0 (a == b) or +1 (a > b) + */ +int lfa_tiebreaker_cmp(const struct lfa_tiebreaker *a, + const struct lfa_tiebreaker *b) +{ + if (a->index < b->index) + return -1; + if (a->index > b->index) + return 1; + + return a->type - b->type; +} + +/** + * Initialize list of LFA tie-breakers. + * + * @param area IS-IS area + * @param level IS-IS level + */ +void isis_lfa_tiebreakers_init(struct isis_area *area, int level) +{ + lfa_tiebreaker_tree_init(&area->lfa_tiebreakers[level - 1]); +} + +/** + * Clear list of LFA tie-breakers, releasing all allocated memory. + * + * @param area IS-IS area + * @param level IS-IS level + */ +void isis_lfa_tiebreakers_clear(struct isis_area *area, int level) +{ + while (lfa_tiebreaker_tree_count(&area->lfa_tiebreakers[level - 1]) + > 0) { + struct lfa_tiebreaker *tie_b; + + tie_b = lfa_tiebreaker_tree_first( + &area->lfa_tiebreakers[level - 1]); + isis_lfa_tiebreaker_delete(area, level, tie_b); + } +} + +/** + * Add new LFA tie-breaker to list of LFA tie-breakers. + * + * @param area IS-IS area + * @param level IS-IS level + * @param index LFA tie-breaker index + * @param type LFA tie-breaker type + * + * @return Pointer to new LFA tie-breaker structure. + */ +struct lfa_tiebreaker *isis_lfa_tiebreaker_add(struct isis_area *area, + int level, uint8_t index, + enum lfa_tiebreaker_type type) +{ + struct lfa_tiebreaker *tie_b; + + tie_b = XCALLOC(MTYPE_ISIS_LFA_TIEBREAKER, sizeof(*tie_b)); + tie_b->index = index; + tie_b->type = type; + tie_b->area = area; + lfa_tiebreaker_tree_add(&area->lfa_tiebreakers[level - 1], tie_b); + + return tie_b; +} + +/** + * Remove LFA tie-breaker from list of LFA tie-breakers. + * + * @param area IS-IS area + * @param level IS-IS level + * @param tie_b Pointer to LFA tie-breaker structure + */ +void isis_lfa_tiebreaker_delete(struct isis_area *area, int level, + struct lfa_tiebreaker *tie_b) +{ + lfa_tiebreaker_tree_del(&area->lfa_tiebreakers[level - 1], tie_b); + XFREE(MTYPE_ISIS_LFA_TIEBREAKER, tie_b); +} + +static bool lfa_excl_interface_hash_cmp(const void *value1, const void *value2) +{ + return strmatch(value1, value2); +} + +static unsigned int lfa_excl_interface_hash_make(const void *value) +{ + return string_hash_make(value); +} + +static void *lfa_excl_interface_hash_alloc(void *p) +{ + return XSTRDUP(MTYPE_ISIS_LFA_EXCL_IFACE, p); +} + +static void lfa_excl_interface_hash_free(void *arg) +{ + XFREE(MTYPE_ISIS_LFA_EXCL_IFACE, arg); +} + +/** + * Initialize hash table of LFA excluded interfaces. + * + * @param circuit IS-IS interface + * @param level IS-IS level + */ +void isis_lfa_excluded_ifaces_init(struct isis_circuit *circuit, int level) +{ + circuit->lfa_excluded_ifaces[level - 1] = hash_create( + lfa_excl_interface_hash_make, lfa_excl_interface_hash_cmp, + "LFA Excluded Interfaces"); +} + +/** + * Clear hash table of LFA excluded interfaces, releasing all allocated memory. + * + * @param nodes List of SPF nodes + */ +void isis_lfa_excluded_ifaces_clear(struct isis_circuit *circuit, int level) +{ + hash_clean(circuit->lfa_excluded_ifaces[level - 1], + lfa_excl_interface_hash_free); +} + +/** + * Add new interface to hash table of excluded interfaces. + * + * @param circuit IS-IS interface + * @param level IS-IS level + * @param ifname Excluded interface name + */ +void isis_lfa_excluded_iface_add(struct isis_circuit *circuit, int level, + const char *ifname) +{ + hash_get(circuit->lfa_excluded_ifaces[level - 1], (char *)ifname, + lfa_excl_interface_hash_alloc); +} + +/** + * Remove interface from hash table of excluded interfaces. + * + * @param circuit IS-IS interface + * @param level IS-IS level + * @param ifname Excluded interface name + */ +void isis_lfa_excluded_iface_delete(struct isis_circuit *circuit, int level, + const char *ifname) +{ + char *found; + + found = hash_lookup(circuit->lfa_excluded_ifaces[level - 1], + (char *)ifname); + if (found) { + hash_release(circuit->lfa_excluded_ifaces[level - 1], found); + lfa_excl_interface_hash_free(found); + } +} + +/** + * Lookup excluded interface. + * + * @param circuit IS-IS interface + * @param level IS-IS level + * @param ifname Excluded interface name + */ +bool isis_lfa_excluded_iface_check(struct isis_circuit *circuit, int level, + const char *ifname) +{ + return hash_lookup(circuit->lfa_excluded_ifaces[level - 1], + (char *)ifname); +} + +/** * Check if a given IS-IS adjacency needs to be excised when computing the SPF * post-convergence tree. * @@ -438,10 +619,10 @@ static int tilfa_build_repair_list(struct isis_spftree *spftree_pc, uint32_t sid_index; mpls_label_t label_qnode; - if (IS_DEBUG_TILFA) { + if (IS_DEBUG_LFA) { vid2string(vertex, buf, sizeof(buf)); - zlog_debug("ISIS-TI-LFA: vertex %s %s", - vtype2string(vertex->type), buf); + zlog_debug("ISIS-LFA: vertex %s %s", vtype2string(vertex->type), + buf); } /* Push original Prefix-SID label when necessary. */ @@ -450,9 +631,9 @@ static int tilfa_build_repair_list(struct isis_spftree *spftree_pc, assert(pvertex); sid_index = vertex->N.ip.sr.sid.value; - if (IS_DEBUG_TILFA) + if (IS_DEBUG_LFA) zlog_debug( - "ISIS-TI-LFA: pushing Prefix-SID to %pFX (index %u)", + "ISIS-LFA: pushing Prefix-SID to %pFX (index %u)", &vertex->N.ip.p.dest, sid_index); sid_dest.type = TILFA_SID_PREFIX; sid_dest.value.index.value = sid_index; @@ -481,14 +662,14 @@ static int tilfa_build_repair_list(struct isis_spftree *spftree_pc, label_qnode = tilfa_find_qnode_adj_sid(spftree_pc, vertex->N.id, vertex_child->N.id); if (label_qnode == MPLS_INVALID_LABEL) { - zlog_warn("ISIS-TI-LFA: failed to find %s->%s Adj-SID", + zlog_warn("ISIS-LFA: failed to find %s->%s Adj-SID", print_sys_hostname(vertex->N.id), print_sys_hostname(vertex_child->N.id)); return -1; } - if (IS_DEBUG_TILFA) + if (IS_DEBUG_LFA) zlog_debug( - "ISIS-TI-LFA: pushing %s->%s Adj-SID (label %u)", + "ISIS-LFA: pushing %s->%s Adj-SID (label %u)", print_sys_hostname(vertex->N.id), print_sys_hostname(vertex_child->N.id), label_qnode); @@ -501,17 +682,17 @@ static int tilfa_build_repair_list(struct isis_spftree *spftree_pc, if (is_pnode) { /* The same P-node can't be used more than once. */ if (isis_spf_node_find(used_pnodes, vertex->N.id)) { - if (IS_DEBUG_TILFA) + if (IS_DEBUG_LFA) zlog_debug( - "ISIS-TI-LFA: skipping already used P-node"); + "ISIS-LFA: skipping already used P-node"); return 0; } isis_spf_node_new(used_pnodes, vertex->N.id); if (!vertex_child) { - if (IS_DEBUG_TILFA) + if (IS_DEBUG_LFA) zlog_debug( - "ISIS-TI-LFA: destination is within Ext-P-Space"); + "ISIS-LFA: destination is within Ext-P-Space"); return 0; } @@ -519,20 +700,29 @@ static int tilfa_build_repair_list(struct isis_spftree *spftree_pc, tilfa_find_pnode_prefix_sid(spftree_pc, vertex->N.id); if (sid_index == UINT32_MAX) { zlog_warn( - "ISIS-TI-LFA: failed to find Prefix-SID corresponding to PQ-node %s", + "ISIS-LFA: failed to find Prefix-SID corresponding to PQ-node %s", print_sys_hostname(vertex->N.id)); return -1; } - if (IS_DEBUG_TILFA) + if (IS_DEBUG_LFA) zlog_debug( - "ISIS-TI-LFA: pushing Node-SID to %s (index %u)", + "ISIS-LFA: pushing Node-SID to %s (index %u)", print_sys_hostname(vertex->N.id), sid_index); sid_pnode.type = TILFA_SID_PREFIX; sid_pnode.value.index.value = sid_index; listnode_add_head(repair_list, &sid_pnode); /* Apply repair list. */ + if (spftree_pc->area->srdb.config.msd + && listcount(repair_list) + > spftree_pc->area->srdb.config.msd) { + zlog_warn( + "ISIS-LFA: list of repair segments exceeds locally configured MSD (%u > %u)", + listcount(repair_list), + spftree_pc->area->srdb.config.msd); + return -1; + } if (tilfa_repair_list_apply(spftree_pc, vertex_dest, vertex, repair_list) != 0) @@ -610,36 +800,25 @@ spf_adj_check_is_affected(const struct isis_spf_adj *sadj, return false; } -/* Check if the given SPF vertex needs LFA protection. */ -static bool lfa_check_needs_protection(const struct isis_spftree *spftree_pc, - const struct isis_vertex *vertex) +/* Check if the given vertex is affected by a given local failure. */ +static bool +spf_vertex_check_is_affected(const struct isis_vertex *vertex, + const uint8_t *root_sysid, + const struct lfa_protected_resource *resource) { - struct isis_vertex *vertex_old; + struct isis_vertex_adj *vadj; struct listnode *node; size_t affected_nhs = 0; - struct isis_vertex_adj *vadj; /* Local routes don't need protection. */ if (VTYPE_IP(vertex->type) && vertex->depth == 1) return false; - /* Only local adjacencies need Adj-SID protection. */ - if (VTYPE_IS(vertex->type) - && !isis_adj_find(spftree_pc->area, spftree_pc->level, - vertex->N.id)) - return false; - - vertex_old = isis_find_vertex(&spftree_pc->lfa.old.spftree->paths, - &vertex->N, vertex->type); - if (!vertex_old) - return false; - - for (ALL_LIST_ELEMENTS_RO(vertex_old->Adj_N, node, vadj)) { + for (ALL_LIST_ELEMENTS_RO(vertex->Adj_N, node, vadj)) { struct isis_spf_adj *sadj = vadj->sadj; - if (spf_adj_check_is_affected( - sadj, &spftree_pc->lfa.protected_resource, - spftree_pc->sysid, false)) + if (spf_adj_check_is_affected(sadj, resource, root_sysid, + false)) affected_nhs++; } @@ -647,12 +826,34 @@ static bool lfa_check_needs_protection(const struct isis_spftree *spftree_pc, * No need to compute backup paths for ECMP routes, except if all * primary nexthops share the same broadcast interface. */ - if (listcount(vertex_old->Adj_N) == affected_nhs) + if (listcount(vertex->Adj_N) == affected_nhs) return true; 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) +{ + struct isis_vertex *vertex_old; + + /* Only local adjacencies need Adj-SID protection. */ + if (VTYPE_IS(vertex->type) + && !isis_adj_find(spftree_pc->area, spftree_pc->level, + vertex->N.id)) + return false; + + vertex_old = isis_find_vertex(&spftree_pc->lfa.old.spftree->paths, + &vertex->N, vertex->type); + if (!vertex_old) + return false; + + return spf_vertex_check_is_affected( + vertex_old, spftree_pc->sysid, + &spftree_pc->lfa.protected_resource); +} + /** * Check if the given SPF vertex needs protection and, if so, compute and * install the corresponding repair paths. @@ -662,7 +863,8 @@ static bool lfa_check_needs_protection(const struct isis_spftree *spftree_pc, * * @return 0 if the vertex needs to be protected, -1 otherwise */ -int isis_lfa_check(struct isis_spftree *spftree_pc, struct isis_vertex *vertex) +int isis_tilfa_check(struct isis_spftree *spftree_pc, + struct isis_vertex *vertex) { struct isis_spf_nodes used_pnodes; char buf[VID2STR_BUFFER]; @@ -672,13 +874,13 @@ int isis_lfa_check(struct isis_spftree *spftree_pc, struct isis_vertex *vertex) if (!spftree_pc->area->srdb.enabled) return -1; - if (IS_DEBUG_TILFA) + if (IS_DEBUG_LFA) vid2string(vertex, buf, sizeof(buf)); - if (!lfa_check_needs_protection(spftree_pc, vertex)) { - if (IS_DEBUG_TILFA) + if (!tilfa_check_needs_protection(spftree_pc, vertex)) { + if (IS_DEBUG_LFA) zlog_debug( - "ISIS-TI-LFA: %s %s unaffected by %s", + "ISIS-LFA: %s %s unaffected by %s", vtype2string(vertex->type), buf, lfa_protected_resource2str( &spftree_pc->lfa.protected_resource)); @@ -697,9 +899,9 @@ int isis_lfa_check(struct isis_spftree *spftree_pc, struct isis_vertex *vertex) if (adj && isis_sr_adj_sid_find(adj, spftree_pc->family, ISIS_SR_LAN_BACKUP)) { - if (IS_DEBUG_TILFA) + if (IS_DEBUG_LFA) zlog_debug( - "ISIS-TI-LFA: %s %s already covered by node protection", + "ISIS-LFA: %s %s already covered by node protection", vtype2string(vertex->type), buf); return -1; @@ -710,18 +912,18 @@ int isis_lfa_check(struct isis_spftree *spftree_pc, struct isis_vertex *vertex) route_table = spftree_pc->lfa.old.spftree->route_table_backup; if (route_node_lookup(route_table, &vertex->N.ip.p.dest)) { - if (IS_DEBUG_TILFA) + if (IS_DEBUG_LFA) zlog_debug( - "ISIS-TI-LFA: %s %s already covered by node protection", + "ISIS-LFA: %s %s already covered by node protection", vtype2string(vertex->type), buf); return -1; } } - if (IS_DEBUG_TILFA) + if (IS_DEBUG_LFA) zlog_debug( - "ISIS-TI-LFA: computing repair path(s) of %s %s w.r.t %s", + "ISIS-LFA: computing repair path(s) of %s %s w.r.t %s", vtype2string(vertex->type), buf, lfa_protected_resource2str( &spftree_pc->lfa.protected_resource)); @@ -735,7 +937,11 @@ int isis_lfa_check(struct isis_spftree *spftree_pc, struct isis_vertex *vertex) isis_spf_node_list_clear(&used_pnodes); list_delete(&repair_list); if (ret != 0) - zlog_warn("ISIS-TI-LFA: failed to compute repair path(s)"); + zlog_warn( + "ISIS-LFA: failed to compute repair path(s) of %s %s w.r.t %s", + vtype2string(vertex->type), buf, + lfa_protected_resource2str( + &spftree_pc->lfa.protected_resource)); return ret; } @@ -775,8 +981,8 @@ static bool vertex_is_affected(struct isis_spftree *spftree_root, char buf1[VID2STR_BUFFER]; char buf2[VID2STR_BUFFER]; - if (IS_DEBUG_TILFA) - zlog_debug("ISIS-TI-LFA: vertex %s parent %s", + if (IS_DEBUG_LFA) + zlog_debug("ISIS-LFA: vertex %s parent %s", vid2string(vertex, buf1, sizeof(buf1)), vid2string(pvertex, buf2, sizeof(buf2))); @@ -853,15 +1059,15 @@ static void lfa_calc_reach_nodes(struct isis_spftree *spftree, if (isis_spf_node_find(nodes, vertex->N.id)) continue; - if (IS_DEBUG_TILFA) - zlog_debug("ISIS-TI-LFA: checking %s", + 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_TILFA) + if (IS_DEBUG_LFA) zlog_debug( - "ISIS-TI-LFA: adding %s", + "ISIS-LFA: adding %s", vid2string(vertex, buf, sizeof(buf))); isis_spf_node_new(nodes, vertex->N.id); @@ -875,7 +1081,7 @@ static void lfa_calc_reach_nodes(struct isis_spftree *spftree, * * @param spftree IS-IS SPF tree * - * @return Pointer to new SPF tree structure. + * @return Pointer to new SPF tree structure. */ struct isis_spftree *isis_spf_reverse_run(const struct isis_spftree *spftree) { @@ -907,18 +1113,17 @@ static void lfa_calc_pq_spaces(struct isis_spftree *spftree_pc, spftree_reverse = spftree_pc->lfa.old.spftree_reverse; adj_nodes = &spftree->adj_nodes; - if (IS_DEBUG_TILFA) - zlog_debug("ISIS-TI-LFA: computing P-space (self)"); + if (IS_DEBUG_LFA) + zlog_debug("ISIS-LFA: computing P-space (self)"); lfa_calc_reach_nodes(spftree, spftree, adj_nodes, true, resource, &spftree_pc->lfa.p_space); RB_FOREACH (adj_node, isis_spf_nodes, adj_nodes) { if (spf_adj_node_is_affected(adj_node, resource, spftree->sysid)) { - if (IS_DEBUG_TILFA) - zlog_debug( - "ISIS-TI-LFA: computing Q-space (%s)", - print_sys_hostname(adj_node->sysid)); + if (IS_DEBUG_LFA) + zlog_debug("ISIS-LFA: computing Q-space (%s)", + print_sys_hostname(adj_node->sysid)); /* * Compute the reverse SPF in the behalf of the node @@ -932,10 +1137,9 @@ static void lfa_calc_pq_spaces(struct isis_spftree *spftree_pc, resource, &spftree_pc->lfa.q_space); } else { - if (IS_DEBUG_TILFA) - zlog_debug( - "ISIS-TI-LFA: computing P-space (%s)", - print_sys_hostname(adj_node->sysid)); + if (IS_DEBUG_LFA) + zlog_debug("ISIS-LFA: computing P-space (%s)", + print_sys_hostname(adj_node->sysid)); lfa_calc_reach_nodes(adj_node->lfa.spftree, spftree, adj_nodes, true, resource, &adj_node->lfa.p_space); @@ -961,8 +1165,8 @@ struct isis_spftree *isis_tilfa_compute(struct isis_area *area, struct isis_spftree *spftree_pc; struct isis_spf_node *adj_node; - if (IS_DEBUG_TILFA) - zlog_debug("ISIS-TI-LFA: computing the P/Q spaces w.r.t. %s", + if (IS_DEBUG_LFA) + zlog_debug("ISIS-LFA: computing the P/Q spaces w.r.t. %s", lfa_protected_resource2str(resource)); /* Populate list of nodes affected by link failure. */ @@ -987,9 +1191,9 @@ struct isis_spftree *isis_tilfa_compute(struct isis_area *area, /* Compute the extended P-space and Q-space. */ lfa_calc_pq_spaces(spftree_pc, resource); - if (IS_DEBUG_TILFA) + if (IS_DEBUG_LFA) zlog_debug( - "ISIS-TI-LFA: computing the post convergence SPT w.r.t. %s", + "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. */ @@ -1019,8 +1223,8 @@ int isis_spf_run_neighbors(struct isis_spftree *spftree) return -1; RB_FOREACH (adj_node, isis_spf_nodes, &spftree->adj_nodes) { - if (IS_DEBUG_TILFA) - zlog_debug("ISIS-TI-LFA: running SPF on neighbor %s", + if (IS_DEBUG_LFA) + zlog_debug("ISIS-LFA: running SPF on neighbor %s", print_sys_hostname(adj_node->sysid)); /* Compute the SPT on behalf of the neighbor. */ @@ -1034,20 +1238,532 @@ int isis_spf_run_neighbors(struct isis_spftree *spftree) return 0; } +/* 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, + uint32_t *distance) +{ + struct isis_vertex *vertex, *vertex_best = NULL; + + switch (spftree->family) { + case AF_INET: + for (int vtype = VTYPE_IPREACH_INTERNAL; + vtype <= VTYPE_IPREACH_TE; vtype++) { + vertex = isis_find_vertex( + &spftree->paths, &vertex_N->N.ip.p.dest, vtype); + if (!vertex) + continue; + + /* Pick vertex with the best metric. */ + if (!vertex_best || vertex_best->d_N > vertex->d_N) + vertex_best = vertex; + } + break; + case AF_INET6: + for (int vtype = VTYPE_IP6REACH_INTERNAL; + vtype <= VTYPE_IP6REACH_EXTERNAL; vtype++) { + vertex = isis_find_vertex( + &spftree->paths, &vertex_N->N.ip.p.dest, vtype); + if (!vertex) + continue; + + /* Pick vertex with the best metric. */ + if (!vertex_best || vertex_best->d_N > vertex->d_N) + vertex_best = vertex; + } + break; + default: + break; + } + + if (!vertex_best) + return -1; + + assert(VTYPE_IP(vertex_best->type)); + vertex_best = listnode_head(vertex_best->parents); + *distance = vertex_best->d_N; + + return 0; +} + +/* Calculate the distance from the root node to the given node. */ +static int lfa_calc_dist_node(struct isis_spftree *spftree, + const uint8_t *sysid, uint32_t *distance) +{ + struct isis_vertex *vertex, *vertex_best = NULL; + + for (int vtype = VTYPE_PSEUDO_IS; vtype <= VTYPE_NONPSEUDO_TE_IS; + vtype++) { + vertex = isis_find_vertex(&spftree->paths, sysid, vtype); + if (!vertex) + continue; + + /* Pick vertex with the best metric. */ + if (!vertex_best || vertex_best->d_N > vertex->d_N) + vertex_best = vertex; + } + + if (!vertex_best) + return -1; + + *distance = vertex_best->d_N; + + return 0; +} + +/* + * Check loop-free criterion (RFC 5286's inequality 1): + * - Dist_opt(N, D) < Dist_opt(N, S) + Dist_opt(S, D) + */ +static bool clfa_loop_free_check(struct isis_spftree *spftree, + struct isis_vertex *vertex_S_D, + struct isis_spf_adj *sadj_primary, + struct isis_spf_adj *sadj_N, + uint32_t *lfa_metric) +{ + struct isis_spf_node *node_N; + uint32_t dist_N_D; + uint32_t dist_N_S; + uint32_t dist_S_D; + + node_N = isis_spf_node_find(&spftree->adj_nodes, sadj_N->id); + assert(node_N); + + /* Distance from N to D. */ + if (lfa_calc_dist_destination(node_N->lfa.spftree, vertex_S_D, + &dist_N_D) + != 0) + return false; + + /* Distance from N to S (or PN). */ + if (CHECK_FLAG(sadj_primary->flags, F_ISIS_SPF_ADJ_BROADCAST)) { + static uint8_t pn_sysid[ISIS_SYS_ID_LEN + 1]; + + memcpy(pn_sysid, sadj_primary->id, ISIS_SYS_ID_LEN + 1); + if (lfa_calc_dist_node(node_N->lfa.spftree, pn_sysid, &dist_N_S) + != 0) + return false; + } else { + static uint8_t root_sysid[ISIS_SYS_ID_LEN + 1]; + + memcpy(root_sysid, spftree->sysid, ISIS_SYS_ID_LEN); + LSP_PSEUDO_ID(root_sysid) = 0; + if (lfa_calc_dist_node(node_N->lfa.spftree, root_sysid, + &dist_N_S) + != 0) + return false; + } + + /* Distance from S (or PN) to D. */ + vertex_S_D = listnode_head(vertex_S_D->parents); + dist_S_D = vertex_S_D->d_N; + if (CHECK_FLAG(sadj_primary->flags, F_ISIS_SPF_ADJ_BROADCAST)) + dist_S_D -= sadj_primary->metric; + + if (IS_DEBUG_LFA) + zlog_debug("ISIS-LFA: loop-free check: %u < %u + %u", dist_N_D, + dist_N_S, dist_S_D); + + if (dist_N_D < (dist_N_S + dist_S_D)) { + *lfa_metric = sadj_N->metric + dist_N_D; + return true; + } + + return false; +} + +/* + * Check loop-free criterion (RFC 5286's inequality 2): + * - Distance_opt(N, D) < Distance_opt(S, D) + */ +static bool clfa_downstream_check(struct isis_spftree *spftree, + struct isis_vertex *vertex_S_D, + struct isis_spf_adj *sadj_N) +{ + struct isis_spf_node *node_N; + uint32_t dist_N_D; + uint32_t dist_S_D; + + node_N = isis_spf_node_find(&spftree->adj_nodes, sadj_N->id); + assert(node_N); + + /* Distance from N to D. */ + if (lfa_calc_dist_destination(node_N->lfa.spftree, vertex_S_D, + &dist_N_D) + != 0) + return false; + + /* Distance from S (or PN) to D. */ + vertex_S_D = listnode_head(vertex_S_D->parents); + dist_S_D = vertex_S_D->d_N; + + if (IS_DEBUG_LFA) + zlog_debug("ISIS-LFA: downstream check: %u < %u", dist_N_D, + dist_S_D); + + if (dist_N_D < dist_S_D) + return true; + + return false; +} + +/* + * Check loop-free criterion (RFC 5286's inequality 3): + * - Dist_opt(N, D) < Dist_opt(N, E) + Dist_opt(E, D) + */ +static bool clfa_node_protecting_check(struct isis_spftree *spftree, + struct isis_vertex *vertex_S_D, + struct isis_spf_adj *sadj_N, + struct isis_spf_adj *sadj_E) +{ + struct isis_spf_node *node_N, *node_E; + uint32_t dist_N_D; + uint32_t dist_N_E; + uint32_t dist_E_D; + + node_N = isis_spf_node_find(&spftree->adj_nodes, sadj_N->id); + assert(node_N); + node_E = isis_spf_node_find(&spftree->adj_nodes, sadj_E->id); + assert(node_E); + + /* Distance from N to D. */ + if (lfa_calc_dist_destination(node_N->lfa.spftree, vertex_S_D, + &dist_N_D) + != 0) + return false; + + /* Distance from N to E. */ + if (lfa_calc_dist_node(node_N->lfa.spftree, node_E->sysid, &dist_N_E) + != 0) + return false; + + /* Distance from E to D. */ + if (lfa_calc_dist_destination(node_E->lfa.spftree, vertex_S_D, + &dist_E_D) + != 0) + return false; + + if (IS_DEBUG_LFA) + zlog_debug("ISIS-LFA: node protecting check: %u < %u + %u", + dist_N_D, dist_N_E, dist_E_D); + + return (dist_N_D < (dist_N_E + dist_E_D)); +} + +static struct list * +isis_lfa_tiebreakers(struct isis_area *area, struct isis_circuit *circuit, + struct isis_spftree *spftree, + struct lfa_protected_resource *resource, + struct isis_vertex *vertex, + struct isis_spf_adj *sadj_primary, struct list *lfa_list) +{ + struct lfa_tiebreaker *tie_b; + int level = spftree->level; + struct list *filtered_lfa_list; + struct list *tent_lfa_list; + + filtered_lfa_list = list_dup(lfa_list); + filtered_lfa_list->del = NULL; + + if (listcount(filtered_lfa_list) == 1) + return filtered_lfa_list; + + /* Check tiebreakers in ascending order by index. */ + frr_each (lfa_tiebreaker_tree, &area->lfa_tiebreakers[level - 1], + tie_b) { + struct isis_vertex_adj *lfa; + struct listnode *node, *nnode; + uint32_t best_metric = UINT32_MAX; + + tent_lfa_list = list_dup(filtered_lfa_list); + + switch (tie_b->type) { + case LFA_TIEBREAKER_DOWNSTREAM: + for (ALL_LIST_ELEMENTS(tent_lfa_list, node, nnode, + lfa)) { + if (clfa_downstream_check(spftree, vertex, + lfa->sadj)) + continue; + + if (IS_DEBUG_LFA) + zlog_debug( + "ISIS-LFA: LFA %s doesn't satisfy the downstream condition", + print_sys_hostname( + lfa->sadj->id)); + listnode_delete(tent_lfa_list, lfa); + } + break; + case LFA_TIEBREAKER_LOWEST_METRIC: + /* Find the best metric first. */ + for (ALL_LIST_ELEMENTS_RO(tent_lfa_list, node, lfa)) { + if (lfa->lfa_metric < best_metric) + best_metric = lfa->lfa_metric; + } + + /* Remove LFAs that don't have the best metric. */ + for (ALL_LIST_ELEMENTS(tent_lfa_list, node, nnode, + lfa)) { + if (lfa->lfa_metric == best_metric) + continue; + + if (IS_DEBUG_LFA) + zlog_debug( + "ISIS-LFA: LFA %s doesn't have the lowest cost metric", + print_sys_hostname( + lfa->sadj->id)); + listnode_delete(tent_lfa_list, lfa); + } + break; + case LFA_TIEBREAKER_NODE_PROTECTING: + for (ALL_LIST_ELEMENTS(tent_lfa_list, node, nnode, + lfa)) { + if (clfa_node_protecting_check(spftree, vertex, + lfa->sadj, + sadj_primary)) + continue; + + if (IS_DEBUG_LFA) + zlog_debug( + "ISIS-LFA: LFA %s doesn't provide node protection", + print_sys_hostname( + lfa->sadj->id)); + listnode_delete(tent_lfa_list, lfa); + } + break; + } + + /* + * Decide what to do next based on the number of remaining LFAs. + */ + switch (listcount(tent_lfa_list)) { + case 0: + /* + * Ignore this tie-breaker since it excluded all LFAs. + * Move on to the next one (if any). + */ + list_delete(&tent_lfa_list); + break; + case 1: + /* Finish tie-breaking once we get a single LFA. */ + list_delete(&filtered_lfa_list); + filtered_lfa_list = tent_lfa_list; + return filtered_lfa_list; + default: + /* + * We still have two or more LFAs. Move on to the next + * tie-breaker (if any). + */ + list_delete(&filtered_lfa_list); + filtered_lfa_list = tent_lfa_list; + break; + } + } + + return filtered_lfa_list; +} + +void isis_lfa_compute(struct isis_area *area, struct isis_circuit *circuit, + struct isis_spftree *spftree, + struct lfa_protected_resource *resource) +{ + struct isis_vertex *vertex; + struct listnode *vnode, *snode; + int level = spftree->level; + + resource->type = LFA_LINK_PROTECTION; + + for (ALL_QUEUE_ELEMENTS_RO(&spftree->paths, vnode, vertex)) { + struct list *lfa_list; + struct list *filtered_lfa_list; + struct isis_spf_adj *sadj_N; + struct isis_vertex_adj *vadj_primary; + struct isis_spf_adj *sadj_primary; + bool allow_ecmp; + uint32_t best_metric = UINT32_MAX; + char buf[VID2STR_BUFFER]; + + if (!VTYPE_IP(vertex->type)) + continue; + + vid2string(vertex, buf, sizeof(buf)); + + if (!spf_vertex_check_is_affected(vertex, spftree->sysid, + resource)) { + if (IS_DEBUG_LFA) + zlog_debug( + "ISIS-LFA: route unaffected by %s", + lfa_protected_resource2str(resource)); + continue; + } + + if (IS_DEBUG_LFA) + zlog_debug("ISIS-LFA: checking %s %s w.r.t %s", + vtype2string(vertex->type), buf, + lfa_protected_resource2str(resource)); + + if (vertex->N.ip.priority + > area->lfa_priority_limit[level - 1]) { + if (IS_DEBUG_LFA) + zlog_debug( + "ISIS-LFA: skipping computing LFAs due to low prefix priority"); + continue; + } + + vadj_primary = listnode_head(vertex->Adj_N); + sadj_primary = vadj_primary->sadj; + + /* + * Loop over list of SPF adjacencies and compute a list of + * preliminary LFAs. + */ + lfa_list = list_new(); + lfa_list->del = isis_vertex_adj_free; + for (ALL_LIST_ELEMENTS_RO(spftree->sadj_list, snode, sadj_N)) { + uint32_t lfa_metric; + struct isis_vertex_adj *lfa; + struct isis_prefix_sid *psid = NULL; + bool last_hop = false; + + /* Skip pseudonodes. */ + if (LSP_PSEUDO_ID(sadj_N->id)) + continue; + + /* + * Skip nexthops that are along a link whose cost is + * infinite. + */ + if (CHECK_FLAG(sadj_N->flags, + F_ISIS_SPF_ADJ_METRIC_INFINITY)) + continue; + + /* Skip nexthops that have the overload bit set. */ + if (spftree->mtid != ISIS_MT_IPV4_UNICAST) { + struct isis_mt_router_info *mt_router_info; + + mt_router_info = + isis_tlvs_lookup_mt_router_info( + sadj_N->lsp->tlvs, + spftree->mtid); + if (mt_router_info && mt_router_info->overload) + continue; + } else if (ISIS_MASK_LSP_OL_BIT( + sadj_N->lsp->hdr.lsp_bits)) + continue; + + /* Skip primary nexthop. */ + if (spf_adj_check_is_affected(sadj_N, resource, NULL, + false)) + continue; + + /* Skip excluded interfaces as per the configuration. */ + if (circuit + && isis_lfa_excluded_iface_check( + circuit, level, + sadj_N->adj->circuit->interface->name)) + continue; + + if (IS_DEBUG_LFA) + zlog_debug( + "ISIS-LFA: checking candidate LFA %s", + print_sys_hostname(sadj_N->id)); + + /* Check loop-free criterion. */ + if (!clfa_loop_free_check(spftree, vertex, sadj_primary, + sadj_N, &lfa_metric)) { + if (IS_DEBUG_LFA) + zlog_debug( + "ISIS-LFA: LFA condition not met for %s", + print_sys_hostname(sadj_N->id)); + continue; + } + + if (lfa_metric < best_metric) + best_metric = lfa_metric; + + if (IS_DEBUG_LFA) + zlog_debug( + "ISIS-LFA: %s is a valid loop-free alternate", + print_sys_hostname(sadj_N->id)); + + if (vertex->N.ip.sr.present) { + psid = &vertex->N.ip.sr.sid; + if (lfa_metric == sadj_N->metric) + last_hop = true; + } + lfa = isis_vertex_adj_add(spftree, vertex, lfa_list, + sadj_N, psid, last_hop); + lfa->lfa_metric = lfa_metric; + } + + if (list_isempty(lfa_list)) { + if (IS_DEBUG_LFA) + zlog_debug("ISIS-LFA: no valid LFAs found"); + list_delete(&lfa_list); + continue; + } + + /* Check tie-breakers. */ + filtered_lfa_list = + isis_lfa_tiebreakers(area, circuit, spftree, resource, + vertex, sadj_primary, lfa_list); + + /* Create backup route using the best LFAs. */ + allow_ecmp = area->lfa_load_sharing[level - 1]; + isis_route_create(&vertex->N.ip.p.dest, &vertex->N.ip.p.src, + best_metric, vertex->depth, &vertex->N.ip.sr, + filtered_lfa_list, allow_ecmp, area, + spftree->route_table_backup); + spftree->lfa.protection_counters.lfa[vertex->N.ip.priority] += + 1; + + list_delete(&filtered_lfa_list); + list_delete(&lfa_list); + } +} + +static void isis_spf_run_tilfa(struct isis_area *area, + struct isis_circuit *circuit, + struct isis_spftree *spftree, + struct isis_spftree *spftree_reverse, + struct lfa_protected_resource *resource) +{ + struct isis_spftree *spftree_pc_link; + struct isis_spftree *spftree_pc_node; + + /* Compute node protecting repair paths first (if necessary). */ + if (circuit->tilfa_node_protection[spftree->level - 1]) { + resource->type = LFA_NODE_PROTECTION; + spftree_pc_node = isis_tilfa_compute(area, spftree, + spftree_reverse, resource); + isis_spftree_del(spftree_pc_node); + } + + /* Compute link protecting repair paths. */ + resource->type = LFA_LINK_PROTECTION; + spftree_pc_link = + isis_tilfa_compute(area, spftree, spftree_reverse, resource); + isis_spftree_del(spftree_pc_link); +} + /** - * Run the TI-LFA algorithm for all proctected interfaces. + * Run the LFA/TI-LFA algorithms for all protected interfaces. * * @param area IS-IS area * @param spftree IS-IS SPF tree */ void isis_spf_run_lfa(struct isis_area *area, struct isis_spftree *spftree) { - struct isis_spftree *spftree_reverse; + 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. */ - spftree_reverse = isis_spf_reverse_run(spftree); + if (tilfa_configured) + spftree_reverse = isis_spf_reverse_run(spftree); /* Run forward SPF on all adjacent routers. */ isis_spf_run_neighbors(spftree); @@ -1056,20 +1772,19 @@ void isis_spf_run_lfa(struct isis_area *area, struct isis_spftree *spftree) for (ALL_LIST_ELEMENTS_RO(area->circuit_list, node, circuit)) { struct lfa_protected_resource resource = {}; struct isis_adjacency *adj; - struct isis_spftree *spftree_pc_link; - struct isis_spftree *spftree_pc_node; static uint8_t null_sysid[ISIS_SYS_ID_LEN + 1]; - if (!(circuit->is_type & spftree->level)) + if (!(circuit->is_type & level)) continue; - if (!circuit->tilfa_protection[spftree->level - 1]) + if (!circuit->lfa_protection[level - 1] + && !circuit->tilfa_protection[level - 1]) continue; /* Fill in the protected resource. */ switch (circuit->circ_type) { case CIRCUIT_T_BROADCAST: - if (spftree->level == 1) + if (level == ISIS_LEVEL1) memcpy(resource.adjacency, circuit->u.bc.l1_desig_is, ISIS_SYS_ID_LEN + 1); @@ -1093,20 +1808,15 @@ void isis_spf_run_lfa(struct isis_area *area, struct isis_spftree *spftree) continue; } - /* Compute node protecting repair paths first (if necessary). */ - if (circuit->tilfa_node_protection[spftree->level - 1]) { - resource.type = LFA_NODE_PROTECTION; - spftree_pc_node = isis_tilfa_compute( - area, spftree, spftree_reverse, &resource); - isis_spftree_del(spftree_pc_node); + if (circuit->lfa_protection[level - 1]) + isis_lfa_compute(area, circuit, spftree, &resource); + else if (circuit->tilfa_protection[level - 1]) { + assert(spftree_reverse); + isis_spf_run_tilfa(area, circuit, spftree, + spftree_reverse, &resource); } - - /* Compute link protecting repair paths. */ - resource.type = LFA_LINK_PROTECTION; - spftree_pc_link = isis_tilfa_compute( - area, spftree, spftree_reverse, &resource); - isis_spftree_del(spftree_pc_link); } - isis_spftree_del(spftree_reverse); + if (tilfa_configured) + isis_spftree_del(spftree_reverse); } diff --git a/isisd/isis_lfa.h b/isisd/isis_lfa.h index 835618760..f09fc663a 100644 --- a/isisd/isis_lfa.h +++ b/isisd/isis_lfa.h @@ -20,6 +20,27 @@ #ifndef _FRR_ISIS_LFA_H #define _FRR_ISIS_LFA_H +#include "lib/typesafe.h" + +PREDECL_RBTREE_UNIQ(lfa_tiebreaker_tree) + +enum lfa_tiebreaker_type { + LFA_TIEBREAKER_DOWNSTREAM = 0, + LFA_TIEBREAKER_LOWEST_METRIC, + LFA_TIEBREAKER_NODE_PROTECTING, +}; + +struct lfa_tiebreaker { + struct lfa_tiebreaker_tree_item entry; + uint8_t index; + enum lfa_tiebreaker_type type; + struct isis_area *area; +}; +int lfa_tiebreaker_cmp(const struct lfa_tiebreaker *a, + const struct lfa_tiebreaker *b); +DECLARE_RBTREE_UNIQ(lfa_tiebreaker_tree, struct lfa_tiebreaker, entry, + lfa_tiebreaker_cmp) + enum isis_tilfa_sid_type { TILFA_SID_PREFIX = 1, TILFA_SID_ADJ, @@ -37,6 +58,20 @@ struct isis_tilfa_sid { } value; }; +enum spf_prefix_priority { + SPF_PREFIX_PRIO_CRITICAL = 0, + SPF_PREFIX_PRIO_HIGH, + SPF_PREFIX_PRIO_MEDIUM, + SPF_PREFIX_PRIO_LOW, + SPF_PREFIX_PRIO_MAX, +}; + +struct spf_prefix_priority_acl { + char *name; + struct access_list *list_v4; + struct access_list *list_v6; +}; + RB_HEAD(isis_spf_nodes, isis_spf_node); RB_PROTOTYPE(isis_spf_nodes, isis_spf_node, entry, isis_spf_node_compare) struct isis_spf_node { @@ -89,14 +124,32 @@ struct isis_spf_node *isis_spf_node_new(struct isis_spf_nodes *nodes, const uint8_t *sysid); struct isis_spf_node *isis_spf_node_find(const struct isis_spf_nodes *nodes, const uint8_t *sysid); +void isis_lfa_tiebreakers_init(struct isis_area *area, int level); +void isis_lfa_tiebreakers_clear(struct isis_area *area, int level); +struct lfa_tiebreaker *isis_lfa_tiebreaker_add(struct isis_area *area, + int level, uint8_t index, + enum lfa_tiebreaker_type type); +void isis_lfa_tiebreaker_delete(struct isis_area *area, int level, + struct lfa_tiebreaker *tie_b); +void isis_lfa_excluded_ifaces_init(struct isis_circuit *circuit, int level); +void isis_lfa_excluded_ifaces_clear(struct isis_circuit *circuit, int level); +void isis_lfa_excluded_iface_add(struct isis_circuit *circuit, int level, + const char *ifname); +void isis_lfa_excluded_iface_delete(struct isis_circuit *circuit, int level, + const char *ifname); +bool isis_lfa_excluded_iface_check(struct isis_circuit *circuit, int level, + const char *ifname); bool isis_lfa_excise_adj_check(const struct isis_spftree *spftree, const uint8_t *id); 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); +void isis_lfa_compute(struct isis_area *area, struct isis_circuit *circuit, + struct isis_spftree *spftree, + struct lfa_protected_resource *resource); void isis_spf_run_lfa(struct isis_area *area, struct isis_spftree *spftree); -int isis_lfa_check(struct isis_spftree *spftree, struct isis_vertex *vertex); +int isis_tilfa_check(struct isis_spftree *spftree, struct isis_vertex *vertex); struct isis_spftree * isis_tilfa_compute(struct isis_area *area, struct isis_spftree *spftree, struct isis_spftree *spftree_reverse, diff --git a/isisd/isis_main.c b/isisd/isis_main.c index 22df3ff37..4576a4a95 100644 --- a/isisd/isis_main.c +++ b/isisd/isis_main.c @@ -242,6 +242,8 @@ int main(int argc, char **argv, char **envp) */ isis_error_init(); access_list_init(); + access_list_add_hook(isis_filter_update); + access_list_delete_hook(isis_filter_update); isis_vrf_init(); prefix_list_init(); isis_init(); diff --git a/isisd/isis_memory.c b/isisd/isis_memory.c index a64decc14..b63a82f40 100644 --- a/isisd/isis_memory.c +++ b/isisd/isis_memory.c @@ -45,3 +45,4 @@ DEFINE_MTYPE(ISISD, ISIS_DICT_NODE, "ISIS dictionary node") 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") diff --git a/isisd/isis_memory.h b/isisd/isis_memory.h index 6b63b3ccb..3ef1c5bf0 100644 --- a/isisd/isis_memory.h +++ b/isisd/isis_memory.h @@ -44,5 +44,6 @@ DECLARE_MTYPE(ISIS_DICT_NODE) DECLARE_MTYPE(ISIS_EXT_ROUTE) DECLARE_MTYPE(ISIS_EXT_INFO) DECLARE_MTYPE(ISIS_MPLS_TE) +DECLARE_MTYPE(ISIS_ACL_NAME) #endif /* _QUAGGA_ISIS_MEMORY_H */ diff --git a/isisd/isis_nb.c b/isisd/isis_nb.c index 2d3c7e1e3..c3d2f238d 100644 --- a/isisd/isis_nb.c +++ b/isisd/isis_nb.c @@ -194,6 +194,30 @@ const struct frr_yang_module_info frr_isisd_info = { }, }, { + .xpath = "/frr-isisd:isis/instance/spf/prefix-priorities/critical/access-list-name", + .cbs = { + .cli_show = cli_show_isis_spf_prefix_priority, + .modify = isis_instance_spf_prefix_priorities_critical_access_list_name_modify, + .destroy = isis_instance_spf_prefix_priorities_critical_access_list_name_destroy, + } + }, + { + .xpath = "/frr-isisd:isis/instance/spf/prefix-priorities/high/access-list-name", + .cbs = { + .cli_show = cli_show_isis_spf_prefix_priority, + .modify = isis_instance_spf_prefix_priorities_high_access_list_name_modify, + .destroy = isis_instance_spf_prefix_priorities_high_access_list_name_destroy, + } + }, + { + .xpath = "/frr-isisd:isis/instance/spf/prefix-priorities/medium/access-list-name", + .cbs = { + .cli_show = cli_show_isis_spf_prefix_priority, + .modify = isis_instance_spf_prefix_priorities_medium_access_list_name_modify, + .destroy = isis_instance_spf_prefix_priorities_medium_access_list_name_destroy, + } + }, + { .xpath = "/frr-isisd:isis/instance/area-password", .cbs = { .apply_finish = area_password_apply_finish, @@ -432,6 +456,64 @@ const struct frr_yang_module_info frr_isisd_info = { }, }, { + .xpath = "/frr-isisd:isis/instance/fast-reroute/level-1/lfa/load-sharing", + .cbs = { + .cli_show = cli_show_isis_frr_lfa_load_sharing, + .modify = isis_instance_fast_reroute_level_1_lfa_load_sharing_modify, + } + }, + { + .xpath = "/frr-isisd:isis/instance/fast-reroute/level-1/lfa/priority-limit", + .cbs = { + .cli_show = cli_show_isis_frr_lfa_priority_limit, + .modify = isis_instance_fast_reroute_level_1_lfa_priority_limit_modify, + .destroy = isis_instance_fast_reroute_level_1_lfa_priority_limit_destroy, + } + }, + { + .xpath = "/frr-isisd:isis/instance/fast-reroute/level-1/lfa/tiebreaker", + .cbs = { + .cli_show = cli_show_isis_frr_lfa_tiebreaker, + .create = isis_instance_fast_reroute_level_1_lfa_tiebreaker_create, + .destroy = isis_instance_fast_reroute_level_1_lfa_tiebreaker_destroy, + } + }, + { + .xpath = "/frr-isisd:isis/instance/fast-reroute/level-1/lfa/tiebreaker/type", + .cbs = { + .modify = isis_instance_fast_reroute_level_1_lfa_tiebreaker_type_modify, + } + }, + { + .xpath = "/frr-isisd:isis/instance/fast-reroute/level-2/lfa/load-sharing", + .cbs = { + .cli_show = cli_show_isis_frr_lfa_load_sharing, + .modify = isis_instance_fast_reroute_level_2_lfa_load_sharing_modify, + } + }, + { + .xpath = "/frr-isisd:isis/instance/fast-reroute/level-2/lfa/priority-limit", + .cbs = { + .cli_show = cli_show_isis_frr_lfa_priority_limit, + .modify = isis_instance_fast_reroute_level_2_lfa_priority_limit_modify, + .destroy = isis_instance_fast_reroute_level_2_lfa_priority_limit_destroy, + } + }, + { + .xpath = "/frr-isisd:isis/instance/fast-reroute/level-2/lfa/tiebreaker", + .cbs = { + .cli_show = cli_show_isis_frr_lfa_tiebreaker, + .create = isis_instance_fast_reroute_level_2_lfa_tiebreaker_create, + .destroy = isis_instance_fast_reroute_level_2_lfa_tiebreaker_destroy, + } + }, + { + .xpath = "/frr-isisd:isis/instance/fast-reroute/level-2/lfa/tiebreaker/type", + .cbs = { + .modify = isis_instance_fast_reroute_level_2_lfa_tiebreaker_type_modify, + } + }, + { .xpath = "/frr-isisd:isis/instance/log-adjacency-changes", .cbs = { .cli_show = cli_show_isis_log_adjacency, @@ -827,7 +909,21 @@ const struct frr_yang_module_info frr_isisd_info = { { .xpath = "/frr-interface:lib/interface/frr-isisd:isis/fast-reroute", .cbs = { - .cli_show = cli_show_ip_isis_ti_lfa, + .cli_show = cli_show_ip_isis_frr, + } + }, + { + .xpath = "/frr-interface:lib/interface/frr-isisd:isis/fast-reroute/level-1/lfa/enable", + .cbs = { + .modify = lib_interface_isis_fast_reroute_level_1_lfa_enable_modify, + } + }, + { + .xpath = "/frr-interface:lib/interface/frr-isisd:isis/fast-reroute/level-1/lfa/exclude-interface", + .cbs = { + .cli_show = cli_show_frr_lfa_exclude_interface, + .create = lib_interface_isis_fast_reroute_level_1_lfa_exclude_interface_create, + .destroy = lib_interface_isis_fast_reroute_level_1_lfa_exclude_interface_destroy, } }, { @@ -843,6 +939,20 @@ const struct frr_yang_module_info frr_isisd_info = { } }, { + .xpath = "/frr-interface:lib/interface/frr-isisd:isis/fast-reroute/level-2/lfa/enable", + .cbs = { + .modify = lib_interface_isis_fast_reroute_level_2_lfa_enable_modify, + } + }, + { + .xpath = "/frr-interface:lib/interface/frr-isisd:isis/fast-reroute/level-2/lfa/exclude-interface", + .cbs = { + .cli_show = cli_show_frr_lfa_exclude_interface, + .create = lib_interface_isis_fast_reroute_level_2_lfa_exclude_interface_create, + .destroy = lib_interface_isis_fast_reroute_level_2_lfa_exclude_interface_destroy, + } + }, + { .xpath = "/frr-interface:lib/interface/frr-isisd:isis/fast-reroute/level-2/ti-lfa/enable", .cbs = { .modify = lib_interface_isis_fast_reroute_level_2_ti_lfa_enable_modify, diff --git a/isisd/isis_nb.h b/isisd/isis_nb.h index fb843131d..f529f2086 100644 --- a/isisd/isis_nb.h +++ b/isisd/isis_nb.h @@ -68,6 +68,18 @@ int isis_instance_spf_minimum_interval_level_1_modify( struct nb_cb_modify_args *args); int isis_instance_spf_minimum_interval_level_2_modify( struct nb_cb_modify_args *args); +int isis_instance_spf_prefix_priorities_critical_access_list_name_modify( + struct nb_cb_modify_args *args); +int isis_instance_spf_prefix_priorities_critical_access_list_name_destroy( + struct nb_cb_destroy_args *args); +int isis_instance_spf_prefix_priorities_high_access_list_name_modify( + struct nb_cb_modify_args *args); +int isis_instance_spf_prefix_priorities_high_access_list_name_destroy( + struct nb_cb_destroy_args *args); +int isis_instance_spf_prefix_priorities_medium_access_list_name_modify( + struct nb_cb_modify_args *args); +int isis_instance_spf_prefix_priorities_medium_access_list_name_destroy( + struct nb_cb_destroy_args *args); int isis_instance_area_password_create(struct nb_cb_create_args *args); int isis_instance_area_password_destroy(struct nb_cb_destroy_args *args); int isis_instance_area_password_password_modify(struct nb_cb_modify_args *args); @@ -159,6 +171,30 @@ int isis_instance_multi_topology_ipv6_dstsrc_destroy( struct nb_cb_destroy_args *args); int isis_instance_multi_topology_ipv6_dstsrc_overload_modify( struct nb_cb_modify_args *args); +int isis_instance_fast_reroute_level_1_lfa_load_sharing_modify( + struct nb_cb_modify_args *args); +int isis_instance_fast_reroute_level_1_lfa_priority_limit_modify( + struct nb_cb_modify_args *args); +int isis_instance_fast_reroute_level_1_lfa_priority_limit_destroy( + struct nb_cb_destroy_args *args); +int isis_instance_fast_reroute_level_1_lfa_tiebreaker_create( + struct nb_cb_create_args *args); +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_2_lfa_load_sharing_modify( + struct nb_cb_modify_args *args); +int isis_instance_fast_reroute_level_2_lfa_priority_limit_modify( + struct nb_cb_modify_args *args); +int isis_instance_fast_reroute_level_2_lfa_priority_limit_destroy( + struct nb_cb_destroy_args *args); +int isis_instance_fast_reroute_level_2_lfa_tiebreaker_create( + struct nb_cb_create_args *args); +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_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); @@ -258,10 +294,22 @@ int lib_interface_isis_multi_topology_ipv6_dstsrc_modify( int lib_interface_isis_mpls_ldp_sync_modify(struct nb_cb_modify_args *args); int lib_interface_isis_mpls_holddown_modify(struct nb_cb_modify_args *args); int lib_interface_isis_mpls_holddown_destroy(struct nb_cb_destroy_args *args); +int lib_interface_isis_fast_reroute_level_1_lfa_enable_modify( + struct nb_cb_modify_args *args); +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_ti_lfa_enable_modify( struct nb_cb_modify_args *args); int lib_interface_isis_fast_reroute_level_1_ti_lfa_node_protection_modify( struct nb_cb_modify_args *args); +int lib_interface_isis_fast_reroute_level_2_lfa_enable_modify( + struct nb_cb_modify_args *args); +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_ti_lfa_enable_modify( struct nb_cb_modify_args *args); int lib_interface_isis_fast_reroute_level_2_ti_lfa_node_protection_modify( @@ -374,6 +422,8 @@ void cli_show_isis_spf_min_interval(struct vty *vty, struct lyd_node *dnode, bool show_defaults); void cli_show_isis_spf_ietf_backoff(struct vty *vty, struct lyd_node *dnode, bool show_defaults); +void cli_show_isis_spf_prefix_priority(struct vty *vty, struct lyd_node *dnode, + bool show_defaults); void cli_show_isis_purge_origin(struct vty *vty, struct lyd_node *dnode, bool show_defaults); void cli_show_isis_mpls_te(struct vty *vty, struct lyd_node *dnode, @@ -410,6 +460,13 @@ void cli_show_isis_node_msd(struct vty *vty, struct lyd_node *dnode, bool show_defaults); void cli_show_isis_prefix_sid(struct vty *vty, struct lyd_node *dnode, bool show_defaults); +void cli_show_isis_frr_lfa_priority_limit(struct vty *vty, + struct lyd_node *dnode, + bool show_defaults); +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_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, @@ -442,8 +499,10 @@ void cli_show_ip_isis_mt_ipv6_mgmt(struct vty *vty, struct lyd_node *dnode, bool show_defaults); void cli_show_ip_isis_mt_ipv6_dstsrc(struct vty *vty, struct lyd_node *dnode, bool show_defaults); -void cli_show_ip_isis_ti_lfa(struct vty *vty, struct lyd_node *dnode, - bool show_defaults); +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_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, diff --git a/isisd/isis_nb_config.c b/isisd/isis_nb_config.c index 45089410e..c12ee44a9 100644 --- a/isisd/isis_nb_config.c +++ b/isisd/isis_nb_config.c @@ -27,6 +27,7 @@ #include "linklist.h" #include "log.h" #include "bfd.h" +#include "filter.h" #include "spf_backoff.h" #include "lib_errors.h" #include "vrf.h" @@ -626,6 +627,145 @@ int isis_instance_spf_minimum_interval_level_2_modify( } /* + * XPath: + * /frr-isisd:isis/instance/spf/prefix-priorities/critical/access-list-name + */ +int isis_instance_spf_prefix_priorities_critical_access_list_name_modify( + struct nb_cb_modify_args *args) +{ + struct isis_area *area; + const char *acl_name; + struct spf_prefix_priority_acl *ppa; + + if (args->event != NB_EV_APPLY) + return NB_OK; + + area = nb_running_get_entry(args->dnode, NULL, true); + acl_name = yang_dnode_get_string(args->dnode, NULL); + + ppa = &area->spf_prefix_priorities[SPF_PREFIX_PRIO_CRITICAL]; + XFREE(MTYPE_ISIS_ACL_NAME, ppa->name); + ppa->name = XSTRDUP(MTYPE_ISIS_ACL_NAME, acl_name); + ppa->list_v4 = access_list_lookup(AFI_IP, acl_name); + ppa->list_v6 = access_list_lookup(AFI_IP6, acl_name); + lsp_regenerate_schedule(area, area->is_type, 0); + + return NB_OK; +} + +int isis_instance_spf_prefix_priorities_critical_access_list_name_destroy( + struct nb_cb_destroy_args *args) +{ + struct isis_area *area; + struct spf_prefix_priority_acl *ppa; + + if (args->event != NB_EV_APPLY) + return NB_OK; + + area = nb_running_get_entry(args->dnode, NULL, true); + + ppa = &area->spf_prefix_priorities[SPF_PREFIX_PRIO_CRITICAL]; + XFREE(MTYPE_ISIS_ACL_NAME, ppa->name); + ppa->list_v4 = NULL; + ppa->list_v6 = NULL; + lsp_regenerate_schedule(area, area->is_type, 0); + + return NB_OK; +} + +/* + * XPath: /frr-isisd:isis/instance/spf/prefix-priorities/high/access-list-name + */ +int isis_instance_spf_prefix_priorities_high_access_list_name_modify( + struct nb_cb_modify_args *args) +{ + struct isis_area *area; + const char *acl_name; + struct spf_prefix_priority_acl *ppa; + + if (args->event != NB_EV_APPLY) + return NB_OK; + + area = nb_running_get_entry(args->dnode, NULL, true); + acl_name = yang_dnode_get_string(args->dnode, NULL); + + ppa = &area->spf_prefix_priorities[SPF_PREFIX_PRIO_HIGH]; + XFREE(MTYPE_ISIS_ACL_NAME, ppa->name); + ppa->name = XSTRDUP(MTYPE_ISIS_ACL_NAME, acl_name); + ppa->list_v4 = access_list_lookup(AFI_IP, acl_name); + ppa->list_v6 = access_list_lookup(AFI_IP6, acl_name); + lsp_regenerate_schedule(area, area->is_type, 0); + + return NB_OK; +} + +int isis_instance_spf_prefix_priorities_high_access_list_name_destroy( + struct nb_cb_destroy_args *args) +{ + struct isis_area *area; + struct spf_prefix_priority_acl *ppa; + + if (args->event != NB_EV_APPLY) + return NB_OK; + + area = nb_running_get_entry(args->dnode, NULL, true); + + ppa = &area->spf_prefix_priorities[SPF_PREFIX_PRIO_HIGH]; + XFREE(MTYPE_ISIS_ACL_NAME, ppa->name); + ppa->list_v4 = NULL; + ppa->list_v6 = NULL; + lsp_regenerate_schedule(area, area->is_type, 0); + + return NB_OK; +} + +/* + * XPath: /frr-isisd:isis/instance/spf/prefix-priorities/medium/access-list-name + */ +int isis_instance_spf_prefix_priorities_medium_access_list_name_modify( + struct nb_cb_modify_args *args) +{ + struct isis_area *area; + const char *acl_name; + struct spf_prefix_priority_acl *ppa; + + if (args->event != NB_EV_APPLY) + return NB_OK; + + area = nb_running_get_entry(args->dnode, NULL, true); + acl_name = yang_dnode_get_string(args->dnode, NULL); + + ppa = &area->spf_prefix_priorities[SPF_PREFIX_PRIO_MEDIUM]; + XFREE(MTYPE_ISIS_ACL_NAME, ppa->name); + ppa->name = XSTRDUP(MTYPE_ISIS_ACL_NAME, acl_name); + ppa->list_v4 = access_list_lookup(AFI_IP, acl_name); + ppa->list_v6 = access_list_lookup(AFI_IP6, acl_name); + lsp_regenerate_schedule(area, area->is_type, 0); + + return NB_OK; +} + +int isis_instance_spf_prefix_priorities_medium_access_list_name_destroy( + struct nb_cb_destroy_args *args) +{ + struct isis_area *area; + struct spf_prefix_priority_acl *ppa; + + if (args->event != NB_EV_APPLY) + return NB_OK; + + area = nb_running_get_entry(args->dnode, NULL, true); + + ppa = &area->spf_prefix_priorities[SPF_PREFIX_PRIO_MEDIUM]; + XFREE(MTYPE_ISIS_ACL_NAME, ppa->name); + ppa->list_v4 = NULL; + ppa->list_v6 = NULL; + lsp_regenerate_schedule(area, area->is_type, 0); + + return NB_OK; +} + +/* * XPath: /frr-isisd:isis/instance/area-password */ void area_password_apply_finish(struct nb_cb_apply_finish_args *args) @@ -1290,6 +1430,229 @@ int isis_instance_multi_topology_ipv6_dstsrc_overload_modify( } /* + * XPath: /frr-isisd:isis/instance/fast-reroute/level-1/lfa/load-sharing + */ +int isis_instance_fast_reroute_level_1_lfa_load_sharing_modify( + struct nb_cb_modify_args *args) +{ + struct isis_area *area; + + if (args->event != NB_EV_APPLY) + return NB_OK; + + area = nb_running_get_entry(args->dnode, NULL, true); + area->lfa_load_sharing[0] = yang_dnode_get_bool(args->dnode, NULL); + lsp_regenerate_schedule(area, area->is_type, 0); + + return NB_OK; +} + +/* + * XPath: /frr-isisd:isis/instance/fast-reroute/level-1/lfa/priority-limit + */ +int isis_instance_fast_reroute_level_1_lfa_priority_limit_modify( + struct nb_cb_modify_args *args) +{ + struct isis_area *area; + + if (args->event != NB_EV_APPLY) + return NB_OK; + + area = nb_running_get_entry(args->dnode, NULL, true); + area->lfa_priority_limit[0] = yang_dnode_get_enum(args->dnode, NULL); + lsp_regenerate_schedule(area, area->is_type, 0); + + return NB_OK; +} + +int isis_instance_fast_reroute_level_1_lfa_priority_limit_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); + area->lfa_priority_limit[0] = SPF_PREFIX_PRIO_LOW; + lsp_regenerate_schedule(area, area->is_type, 0); + + return NB_OK; +} + +/* + * XPath: /frr-isisd:isis/instance/fast-reroute/level-1/lfa/tiebreaker + */ +int isis_instance_fast_reroute_level_1_lfa_tiebreaker_create( + struct nb_cb_create_args *args) +{ + struct isis_area *area; + uint8_t index; + enum lfa_tiebreaker_type type; + struct lfa_tiebreaker *tie_b; + + if (args->event != NB_EV_APPLY) + return NB_OK; + + area = nb_running_get_entry(args->dnode, NULL, true); + index = yang_dnode_get_uint8(args->dnode, "./index"); + type = yang_dnode_get_enum(args->dnode, "./type"); + + tie_b = isis_lfa_tiebreaker_add(area, ISIS_LEVEL1, index, type); + nb_running_set_entry(args->dnode, tie_b); + lsp_regenerate_schedule(area, area->is_type, 0); + + return NB_OK; +} + +int isis_instance_fast_reroute_level_1_lfa_tiebreaker_destroy( + struct nb_cb_destroy_args *args) +{ + struct lfa_tiebreaker *tie_b; + struct isis_area *area; + + if (args->event != NB_EV_APPLY) + return NB_OK; + + tie_b = nb_running_unset_entry(args->dnode); + area = tie_b->area; + isis_lfa_tiebreaker_delete(area, ISIS_LEVEL1, tie_b); + lsp_regenerate_schedule(area, area->is_type, 0); + + return NB_OK; +} + +/* + * XPath: /frr-isisd:isis/instance/fast-reroute/level-1/lfa/tiebreaker/type + */ +int isis_instance_fast_reroute_level_1_lfa_tiebreaker_type_modify( + struct nb_cb_modify_args *args) +{ + struct lfa_tiebreaker *tie_b; + struct isis_area *area; + + if (args->event != NB_EV_APPLY) + return NB_OK; + + tie_b = nb_running_get_entry(args->dnode, NULL, true); + area = tie_b->area; + tie_b->type = yang_dnode_get_enum(args->dnode, NULL); + lsp_regenerate_schedule(area, area->is_type, 0); + + return NB_OK; +} + +/* + * XPath: /frr-isisd:isis/instance/fast-reroute/level-2/lfa/load-sharing + */ +int isis_instance_fast_reroute_level_2_lfa_load_sharing_modify( + struct nb_cb_modify_args *args) +{ + struct isis_area *area; + + if (args->event != NB_EV_APPLY) + return NB_OK; + + area = nb_running_get_entry(args->dnode, NULL, true); + area->lfa_load_sharing[1] = yang_dnode_get_bool(args->dnode, NULL); + + return NB_OK; +} + +/* + * XPath: /frr-isisd:isis/instance/fast-reroute/level-2/lfa/priority-limit + */ +int isis_instance_fast_reroute_level_2_lfa_priority_limit_modify( + struct nb_cb_modify_args *args) +{ + struct isis_area *area; + + if (args->event != NB_EV_APPLY) + return NB_OK; + + area = nb_running_get_entry(args->dnode, NULL, true); + area->lfa_priority_limit[1] = yang_dnode_get_enum(args->dnode, NULL); + + return NB_OK; +} + +int isis_instance_fast_reroute_level_2_lfa_priority_limit_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); + area->lfa_priority_limit[1] = SPF_PREFIX_PRIO_LOW; + + return NB_OK; +} + +/* + * XPath: /frr-isisd:isis/instance/fast-reroute/level-2/lfa/tiebreaker + */ +int isis_instance_fast_reroute_level_2_lfa_tiebreaker_create( + struct nb_cb_create_args *args) +{ + struct isis_area *area; + uint8_t index; + enum lfa_tiebreaker_type type; + struct lfa_tiebreaker *tie_b; + + if (args->event != NB_EV_APPLY) + return NB_OK; + + area = nb_running_get_entry(args->dnode, NULL, true); + index = yang_dnode_get_uint8(args->dnode, "./index"); + type = yang_dnode_get_enum(args->dnode, "./type"); + + tie_b = isis_lfa_tiebreaker_add(area, ISIS_LEVEL2, index, type); + nb_running_set_entry(args->dnode, tie_b); + lsp_regenerate_schedule(area, area->is_type, 0); + + return NB_OK; +} + +int isis_instance_fast_reroute_level_2_lfa_tiebreaker_destroy( + struct nb_cb_destroy_args *args) +{ + struct lfa_tiebreaker *tie_b; + struct isis_area *area; + + if (args->event != NB_EV_APPLY) + return NB_OK; + + tie_b = nb_running_unset_entry(args->dnode); + area = tie_b->area; + isis_lfa_tiebreaker_delete(area, ISIS_LEVEL2, tie_b); + lsp_regenerate_schedule(area, area->is_type, 0); + + return NB_OK; +} + +/* + * XPath: /frr-isisd:isis/instance/fast-reroute/level-2/lfa/tiebreaker/type + */ +int isis_instance_fast_reroute_level_2_lfa_tiebreaker_type_modify( + struct nb_cb_modify_args *args) +{ + struct lfa_tiebreaker *tie_b; + struct isis_area *area; + + if (args->event != NB_EV_APPLY) + return NB_OK; + + tie_b = nb_running_get_entry(args->dnode, NULL, true); + area = tie_b->area; + tie_b->type = yang_dnode_get_enum(args->dnode, NULL); + lsp_regenerate_schedule(area, area->is_type, 0); + + return NB_OK; +} + +/* * XPath: /frr-isisd:isis/instance/log-adjacency-changes */ int isis_instance_log_adjacency_changes_modify(struct nb_cb_modify_args *args) @@ -3005,6 +3368,78 @@ int lib_interface_isis_mpls_holddown_destroy(struct nb_cb_destroy_args *args) /* * XPath: + * /frr-interface:lib/interface/frr-isisd:isis/fast-reroute/level-1/lfa/enable + */ +int lib_interface_isis_fast_reroute_level_1_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->lfa_protection[0] = yang_dnode_get_bool(args->dnode, NULL); + if (circuit->lfa_protection[0]) + circuit->area->lfa_protected_links[0]++; + else { + assert(circuit->area->lfa_protected_links[0] > 0); + circuit->area->lfa_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/lfa/exclude-interface + */ +int lib_interface_isis_fast_reroute_level_1_lfa_exclude_interface_create( + struct nb_cb_create_args *args) +{ + struct isis_area *area; + struct isis_circuit *circuit; + const char *exclude_ifname; + + if (args->event != NB_EV_APPLY) + return NB_OK; + + circuit = nb_running_get_entry(args->dnode, NULL, true); + exclude_ifname = yang_dnode_get_string(args->dnode, NULL); + + isis_lfa_excluded_iface_add(circuit, ISIS_LEVEL1, exclude_ifname); + area = circuit->area; + lsp_regenerate_schedule(area, area->is_type, 0); + + return NB_OK; +} + +int lib_interface_isis_fast_reroute_level_1_lfa_exclude_interface_destroy( + struct nb_cb_destroy_args *args) +{ + struct isis_area *area; + struct isis_circuit *circuit; + const char *exclude_ifname; + + if (args->event != NB_EV_APPLY) + return NB_OK; + + circuit = nb_running_get_entry(args->dnode, NULL, true); + exclude_ifname = yang_dnode_get_string(args->dnode, NULL); + + isis_lfa_excluded_iface_delete(circuit, ISIS_LEVEL1, exclude_ifname); + 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 */ int lib_interface_isis_fast_reroute_level_1_ti_lfa_enable_modify( @@ -3019,10 +3454,10 @@ int lib_interface_isis_fast_reroute_level_1_ti_lfa_enable_modify( circuit = nb_running_get_entry(args->dnode, NULL, true); circuit->tilfa_protection[0] = yang_dnode_get_bool(args->dnode, NULL); if (circuit->tilfa_protection[0]) - circuit->area->lfa_protected_links[0]++; + circuit->area->tilfa_protected_links[0]++; else { - assert(circuit->area->lfa_protected_links[0] > 0); - circuit->area->lfa_protected_links[0]--; + assert(circuit->area->tilfa_protected_links[0] > 0); + circuit->area->tilfa_protected_links[0]--; } area = circuit->area; @@ -3056,6 +3491,78 @@ int lib_interface_isis_fast_reroute_level_1_ti_lfa_node_protection_modify( /* * XPath: + * /frr-interface:lib/interface/frr-isisd:isis/fast-reroute/level-2/lfa/enable + */ +int lib_interface_isis_fast_reroute_level_2_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->lfa_protection[1] = yang_dnode_get_bool(args->dnode, NULL); + if (circuit->lfa_protection[1]) + circuit->area->lfa_protected_links[1]++; + else { + assert(circuit->area->lfa_protected_links[1] > 0); + circuit->area->lfa_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/lfa/exclude-interface + */ +int lib_interface_isis_fast_reroute_level_2_lfa_exclude_interface_create( + struct nb_cb_create_args *args) +{ + struct isis_area *area; + struct isis_circuit *circuit; + const char *exclude_ifname; + + if (args->event != NB_EV_APPLY) + return NB_OK; + + circuit = nb_running_get_entry(args->dnode, NULL, true); + exclude_ifname = yang_dnode_get_string(args->dnode, NULL); + + isis_lfa_excluded_iface_add(circuit, ISIS_LEVEL2, exclude_ifname); + area = circuit->area; + lsp_regenerate_schedule(area, area->is_type, 0); + + return NB_OK; +} + +int lib_interface_isis_fast_reroute_level_2_lfa_exclude_interface_destroy( + struct nb_cb_destroy_args *args) +{ + struct isis_area *area; + struct isis_circuit *circuit; + const char *exclude_ifname; + + if (args->event != NB_EV_APPLY) + return NB_OK; + + circuit = nb_running_get_entry(args->dnode, NULL, true); + exclude_ifname = yang_dnode_get_string(args->dnode, NULL); + + isis_lfa_excluded_iface_delete(circuit, ISIS_LEVEL2, exclude_ifname); + 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 */ int lib_interface_isis_fast_reroute_level_2_ti_lfa_enable_modify( @@ -3070,10 +3577,10 @@ int lib_interface_isis_fast_reroute_level_2_ti_lfa_enable_modify( circuit = nb_running_get_entry(args->dnode, NULL, true); circuit->tilfa_protection[1] = yang_dnode_get_bool(args->dnode, NULL); if (circuit->tilfa_protection[1]) - circuit->area->lfa_protected_links[1]++; + circuit->area->tilfa_protected_links[1]++; else { - assert(circuit->area->lfa_protected_links[1] > 0); - circuit->area->lfa_protected_links[1]--; + assert(circuit->area->tilfa_protected_links[1] > 0); + circuit->area->tilfa_protected_links[1]--; } area = circuit->area; diff --git a/isisd/isis_route.c b/isisd/isis_route.c index d664a6f89..d32f219e9 100644 --- a/isisd/isis_route.c +++ b/isisd/isis_route.c @@ -183,7 +183,7 @@ static void isis_route_add_dummy_nexthops(struct isis_route_info *rinfo, static struct isis_route_info * isis_route_info_new(struct prefix *prefix, struct prefix_ipv6 *src_p, uint32_t cost, uint32_t depth, struct isis_sr_psid_info *sr, - struct list *adjacencies) + struct list *adjacencies, bool allow_ecmp) { struct isis_route_info *rinfo; struct isis_vertex_adj *vadj; @@ -205,6 +205,8 @@ isis_route_info_new(struct prefix *prefix, struct prefix_ipv6 *src_p, if (CHECK_FLAG(im->options, F_ISIS_UNIT_TEST)) { isis_route_add_dummy_nexthops(rinfo, sadj->id, sr, label_stack); + if (!allow_ecmp) + break; continue; } @@ -233,6 +235,8 @@ isis_route_info_new(struct prefix *prefix, struct prefix_ipv6 *src_p, } adjinfo2nexthop(prefix->family, rinfo->nexthops, adj, sr, label_stack); + if (!allow_ecmp) + break; } rinfo->cost = cost; @@ -339,8 +343,8 @@ static int isis_route_info_same(struct isis_route_info *new, struct isis_route_info * 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, struct isis_area *area, - struct route_table *table) + struct list *adjacencies, bool allow_ecmp, + struct isis_area *area, struct route_table *table) { struct route_node *route_node; struct isis_route_info *rinfo_new, *rinfo_old, *route_info = NULL; @@ -350,7 +354,7 @@ isis_route_create(struct prefix *prefix, struct prefix_ipv6 *src_p, return NULL; rinfo_new = isis_route_info_new(prefix, src_p, cost, depth, sr, - adjacencies); + adjacencies, allow_ecmp); route_node = srcdest_rnode_get(table, prefix, src_p); rinfo_old = route_node->info; diff --git a/isisd/isis_route.h b/isisd/isis_route.h index b5e4aed6c..0d4f88495 100644 --- a/isisd/isis_route.h +++ b/isisd/isis_route.h @@ -61,8 +61,8 @@ void adjinfo2nexthop(int family, struct list *nexthops, struct isis_route_info * 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, struct isis_area *area, - struct route_table *table); + struct list *adjacencies, bool allow_ecmp, + struct isis_area *area, 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 */ diff --git a/isisd/isis_spf.c b/isisd/isis_spf.c index 58b0cf268..47918ef47 100644 --- a/isisd/isis_spf.c +++ b/isisd/isis_spf.c @@ -32,6 +32,7 @@ #include "termtable.h" #include "memory.h" #include "prefix.h" +#include "filter.h" #include "if.h" #include "hash.h" #include "table.h" @@ -216,7 +217,7 @@ struct isis_vertex *isis_spf_prefix_sid_lookup(struct isis_spftree *spftree, return hash_lookup(spftree->prefix_sids, &lookup); } -static void isis_vertex_adj_free(void *arg) +void isis_vertex_adj_free(void *arg) { struct isis_vertex_adj *vadj = arg; @@ -246,10 +247,10 @@ static struct isis_vertex *isis_vertex_new(struct isis_spftree *spftree, return vertex; } -static struct isis_vertex_adj *isis_vertex_adj_add(struct isis_spftree *spftree, - struct isis_vertex *vertex, - struct isis_spf_adj *sadj, - struct isis_prefix_sid *psid) +struct isis_vertex_adj * +isis_vertex_adj_add(struct isis_spftree *spftree, struct isis_vertex *vertex, + struct list *vadj_list, struct isis_spf_adj *sadj, + struct isis_prefix_sid *psid, bool last_hop) { struct isis_vertex_adj *vadj; @@ -262,9 +263,6 @@ static struct isis_vertex_adj *isis_vertex_adj_add(struct isis_spftree *spftree, "ISIS-SPF: ignoring different Prefix-SID for route %pFX", &vertex->N.ip.p.dest); else { - bool last_hop; - - last_hop = (vertex->depth == 2); vadj->sr.sid = *psid; vadj->sr.label = sr_prefix_out_label( spftree->lspdb, vertex->N.ip.p.dest.family, @@ -273,7 +271,7 @@ static struct isis_vertex_adj *isis_vertex_adj_add(struct isis_spftree *spftree, vadj->sr.present = true; } } - listnode_add(vertex->Adj_N, vadj); + listnode_add(vadj_list, vadj); return vadj; } @@ -528,6 +526,7 @@ isis_spf_add2tent(struct isis_spftree *spftree, enum vertextype vtype, void *id, { struct isis_vertex *vertex; struct listnode *node; + bool last_hop; char buff[VID2STR_BUFFER]; vertex = isis_find_vertex(&spftree->paths, id, vtype); @@ -593,14 +592,16 @@ isis_spf_add2tent(struct isis_spftree *spftree, enum vertextype vtype, void *id, if (CHECK_FLAG(spftree->flags, F_SPFTREE_HOPCOUNT_METRIC)) vertex_update_firsthops(vertex, parent); + last_hop = (vertex->depth == 2); if (parent && parent->Adj_N && listcount(parent->Adj_N) > 0) { struct isis_vertex_adj *parent_vadj; for (ALL_LIST_ELEMENTS_RO(parent->Adj_N, node, parent_vadj)) - isis_vertex_adj_add(spftree, vertex, parent_vadj->sadj, - psid); + isis_vertex_adj_add(spftree, vertex, vertex->Adj_N, + parent_vadj->sadj, psid, last_hop); } else if (sadj) { - isis_vertex_adj_add(spftree, vertex, sadj, psid); + isis_vertex_adj_add(spftree, vertex, vertex->Adj_N, sadj, psid, + last_hop); } #ifdef EXTREME_DEBUG @@ -628,9 +629,13 @@ static void isis_spf_add_local(struct isis_spftree *spftree, if (vertex) { /* C.2.5 c) */ if (vertex->d_N == cost) { - if (sadj) - isis_vertex_adj_add(spftree, vertex, sadj, - psid); + if (sadj) { + bool last_hop = (vertex->depth == 2); + + isis_vertex_adj_add(spftree, vertex, + vertex->Adj_N, sadj, psid, + last_hop); + } /* d) */ if (!CHECK_FLAG(spftree->flags, F_SPFTREE_NO_ADJACENCIES) @@ -718,11 +723,16 @@ static void process_N(struct isis_spftree *spftree, enum vertextype vtype, struct isis_vertex_adj *parent_vadj; for (ALL_LIST_ELEMENTS_RO(parent->Adj_N, node, parent_vadj)) - if (!isis_vertex_adj_exists(spftree, vertex, - parent_vadj->sadj)) + if (!isis_vertex_adj_exists( + spftree, vertex, + parent_vadj->sadj)) { + bool last_hop = (vertex->depth == 2); + isis_vertex_adj_add(spftree, vertex, + vertex->Adj_N, parent_vadj->sadj, - psid); + psid, last_hop); + } if (CHECK_FLAG(spftree->flags, F_SPFTREE_HOPCOUNT_METRIC)) vertex_update_firsthops(vertex, parent); @@ -771,7 +781,7 @@ static int isis_spf_process_lsp(struct isis_spftree *spftree, bool has_valid_psid; if (isis_lfa_excise_node_check(spftree, lsp->hdr.lsp_id)) { - if (IS_DEBUG_TILFA) + if (IS_DEBUG_LFA) zlog_debug("ISIS-LFA: excising node %s", print_sys_hostname(lsp->hdr.lsp_id)); return ISIS_OK; @@ -1140,7 +1150,7 @@ static void isis_spf_preload_tent(struct isis_spftree *spftree, adj_id = sadj->id; if (isis_lfa_excise_adj_check(spftree, adj_id)) { - if (IS_DEBUG_TILFA) + if (IS_DEBUG_LFA) zlog_debug("ISIS-SPF: excising adjacency %s", isis_format_id(sadj->id, ISIS_SYS_ID_LEN + 1)); @@ -1158,9 +1168,9 @@ static void isis_spf_preload_tent(struct isis_spftree *spftree, : VTYPE_NONPSEUDO_TE_IS, sadj->id, sadj, metric, NULL, parent); - } else if (sadj->lan.lsp_pseudo) { - isis_spf_process_lsp(spftree, sadj->lan.lsp_pseudo, - metric, 0, spftree->sysid, parent); + } else if (sadj->lsp) { + isis_spf_process_lsp(spftree, sadj->lsp, metric, 0, + spftree->sysid, parent); } } } @@ -1243,12 +1253,24 @@ static void spf_adj_list_parse_tlv(struct isis_spftree *spftree, struct isis_ext_subtlvs *subtlvs) { struct isis_spf_adj *sadj; + uint8_t lspid[ISIS_SYS_ID_LEN + 2]; + struct isis_lsp *lsp; uint8_t flags = 0; /* Skip self in the pseudonode. */ if (desig_is_id && !memcmp(id, spftree->sysid, ISIS_SYS_ID_LEN)) return; + /* Find LSP from the adjacency. */ + memcpy(lspid, id, ISIS_SYS_ID_LEN + 1); + LSP_FRAGMENT(lspid) = 0; + lsp = lsp_search(spftree->lspdb, lspid); + if (lsp == NULL || lsp->hdr.rem_lifetime == 0) { + zlog_warn("ISIS-SPF: No LSP found from root to L%d %s", + spftree->level, rawlspid_print(id)); + return; + } + sadj = XCALLOC(MTYPE_ISIS_SPF_ADJ, sizeof(*sadj)); memcpy(sadj->id, id, sizeof(sadj->id)); if (desig_is_id) { @@ -1260,9 +1282,14 @@ static void spf_adj_list_parse_tlv(struct isis_spftree *spftree, sadj->metric = metric; if (oldmetric) SET_FLAG(flags, F_ISIS_SPF_ADJ_OLDMETRIC); + sadj->lsp = lsp; sadj->subtlvs = subtlvs; sadj->flags = flags; + if ((oldmetric && metric == ISIS_NARROW_METRIC_INFINITY) + || (!oldmetric && metric == ISIS_WIDE_METRIC_INFINITY)) + SET_FLAG(flags, F_ISIS_SPF_ADJ_METRIC_INFINITY); + /* Set real adjacency. */ if (!CHECK_FLAG(spftree->flags, F_SPFTREE_NO_ADJACENCIES) && !LSP_PSEUDO_ID(id)) { @@ -1294,24 +1321,8 @@ static void spf_adj_list_parse_tlv(struct isis_spftree *spftree, } /* Parse pseudonode LSP too. */ - if (LSP_PSEUDO_ID(id)) { - uint8_t lspid[ISIS_SYS_ID_LEN + 2]; - struct isis_lsp *lsp_pseudo; - - memcpy(lspid, id, ISIS_SYS_ID_LEN + 1); - LSP_FRAGMENT(lspid) = 0; - lsp_pseudo = lsp_search(spftree->lspdb, lspid); - if (lsp_pseudo == NULL || lsp_pseudo->hdr.rem_lifetime == 0) { - zlog_warn( - "ISIS-SPF: No LSP found from root to L%d DR %s", - spftree->level, rawlspid_print(id)); - return; - } - - sadj->lan.lsp_pseudo = lsp_pseudo; - spf_adj_list_parse_lsp(spftree, adj_list, lsp_pseudo, id, - metric); - } + if (LSP_PSEUDO_ID(id)) + spf_adj_list_parse_lsp(spftree, adj_list, lsp, id, metric); } static void spf_adj_list_parse_lsp(struct isis_spftree *spftree, @@ -1418,32 +1429,65 @@ 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); + memset(&spftree->lfa.protection_counters, 0, + sizeof(spftree->lfa.protection_counters)); spftree->mtid = mtid; } +static enum spf_prefix_priority +spf_prefix_priority(struct isis_spftree *spftree, struct isis_vertex *vertex) +{ + struct isis_area *area = spftree->area; + struct prefix *prefix = &vertex->N.ip.p.dest; + + for (int priority = SPF_PREFIX_PRIO_CRITICAL; + priority <= SPF_PREFIX_PRIO_MEDIUM; priority++) { + struct spf_prefix_priority_acl *ppa; + enum filter_type ret = FILTER_PERMIT; + + ppa = &area->spf_prefix_priorities[priority]; + switch (spftree->family) { + case AF_INET: + ret = access_list_apply(ppa->list_v4, prefix); + break; + case AF_INET6: + ret = access_list_apply(ppa->list_v6, prefix); + break; + default: + break; + } + + if (ret == FILTER_PERMIT) + return priority; + } + + /* Assign medium priority to loopback prefixes by default. */ + if (is_host_route(prefix)) + return SPF_PREFIX_PRIO_MEDIUM; + + return SPF_PREFIX_PRIO_LOW; +} + static void spf_path_process(struct isis_spftree *spftree, struct isis_vertex *vertex) { struct isis_area *area = spftree->area; + int level = spftree->level; char buff[VID2STR_BUFFER]; - if (VTYPE_IS(vertex->type) + if (spftree->type == SPF_TYPE_TI_LFA && VTYPE_IS(vertex->type) && !CHECK_FLAG(spftree->flags, F_SPFTREE_NO_ADJACENCIES)) { if (listcount(vertex->Adj_N) > 0) { - if (spftree->type == SPF_TYPE_TI_LFA) { - struct isis_adjacency *adj; + struct isis_adjacency *adj; - if (isis_lfa_check(spftree, vertex) != 0) - return; + if (isis_tilfa_check(spftree, vertex) != 0) + return; - adj = isis_adj_find(area, spftree->level, - vertex->N.id); - if (adj) - sr_adj_sid_add_single( - adj, spftree->family, true, - vertex->Adj_N); - } + adj = isis_adj_find(area, level, vertex->N.id); + if (adj) + sr_adj_sid_add_single(adj, spftree->family, + true, vertex->Adj_N); } else if (IS_DEBUG_SPF_EVENTS) zlog_debug( "ISIS-SPF: no adjacencies, do not install backup Adj-SID for %s depth %d dist %d", @@ -1453,21 +1497,59 @@ static void spf_path_process(struct isis_spftree *spftree, if (VTYPE_IP(vertex->type) && !CHECK_FLAG(spftree->flags, F_SPFTREE_NO_ROUTES)) { + enum spf_prefix_priority priority; + + priority = spf_prefix_priority(spftree, vertex); + vertex->N.ip.priority = priority; if (vertex->depth == 1 || listcount(vertex->Adj_N) > 0) { struct route_table *route_table; + bool allow_ecmp; if (spftree->type == SPF_TYPE_TI_LFA) { - if (isis_lfa_check(spftree, vertex) != 0) + struct isis_spftree *pre_spftree; + + if (priority + > area->lfa_priority_limit[level - 1]) { + if (IS_DEBUG_LFA) + zlog_debug( + "ISIS-LFA: skipping %s %s (low prefix priority)", + vtype2string( + vertex->type), + vid2string( + vertex, buff, + sizeof(buff))); return; - route_table = spftree->lfa.old.spftree - ->route_table_backup; - } else + } + + if (isis_tilfa_check(spftree, vertex) != 0) + return; + + pre_spftree = spftree->lfa.old.spftree; + route_table = pre_spftree->route_table_backup; + allow_ecmp = area->lfa_load_sharing[level - 1]; + pre_spftree->lfa.protection_counters + .tilfa[vertex->N.ip.priority] += 1; + } else { route_table = spftree->route_table; + allow_ecmp = true; + + /* + * Update LFA protection counters (ignore local + * routes). + */ + if (vertex->depth > 1) { + spftree->lfa.protection_counters + .total[priority] += 1; + if (listcount(vertex->Adj_N) > 1) + spftree->lfa.protection_counters + .ecmp[priority] += 1; + } + } - 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, area, route_table); + 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, allow_ecmp, area, route_table); } else if (IS_DEBUG_SPF_EVENTS) zlog_debug( "ISIS-SPF: no adjacencies, do not install route for %s depth %d dist %d", @@ -1641,7 +1723,8 @@ static void isis_run_spf_with_protection(struct isis_area *area, isis_run_spf(spftree); /* Run LFA protection if configured. */ - if (area->lfa_protected_links[spftree->level - 1] > 0) + if (area->lfa_protected_links[spftree->level - 1] > 0 + || area->tilfa_protected_links[spftree->level - 1] > 0) isis_spf_run_lfa(area, spftree); } @@ -2281,10 +2364,223 @@ DEFUN(show_isis_route, show_isis_route_cmd, return CMD_SUCCESS; } +static void isis_print_frr_summary_line(struct ttable *tt, + const char *protection, + uint32_t counters[SPF_PREFIX_PRIO_MAX]) +{ + uint32_t critical, high, medium, low, total; + + critical = counters[SPF_PREFIX_PRIO_CRITICAL]; + high = counters[SPF_PREFIX_PRIO_HIGH]; + medium = counters[SPF_PREFIX_PRIO_MEDIUM]; + low = counters[SPF_PREFIX_PRIO_LOW]; + total = critical + high + medium + low; + + ttable_add_row(tt, "%s|%u|%u|%u|%u|%u", protection, critical, high, + medium, low, total); +} + +static void +isis_print_frr_summary_line_coverage(struct ttable *tt, const char *protection, + double counters[SPF_PREFIX_PRIO_MAX], + double total) +{ + double critical, high, medium, low; + + critical = counters[SPF_PREFIX_PRIO_CRITICAL] * 100; + high = counters[SPF_PREFIX_PRIO_HIGH] * 100; + medium = counters[SPF_PREFIX_PRIO_MEDIUM] * 100; + low = counters[SPF_PREFIX_PRIO_LOW] * 100; + total *= 100; + + ttable_add_row(tt, "%s|%.2f%%|%.2f%%|%.2f%%|%.2f%%|%.2f%%", protection, + critical, high, medium, low, total); +} + +static void isis_print_frr_summary(struct vty *vty, + struct isis_spftree *spftree) +{ + struct ttable *tt; + char *table; + const char *tree_id_text = NULL; + uint32_t protectd[SPF_PREFIX_PRIO_MAX] = {0}; + uint32_t unprotected[SPF_PREFIX_PRIO_MAX] = {0}; + double coverage[SPF_PREFIX_PRIO_MAX] = {0}; + uint32_t protected_total = 0, grand_total = 0; + double coverage_total; + + if (!spftree) + return; + + switch (spftree->tree_id) { + case SPFTREE_IPV4: + tree_id_text = "IPv4"; + break; + case SPFTREE_IPV6: + tree_id_text = "IPv6"; + break; + case SPFTREE_DSTSRC: + tree_id_text = "IPv6 (dst-src routing)"; + break; + case SPFTREE_COUNT: + assert(!"isis_print_frr_summary shouldn't be called with SPFTREE_COUNT as type"); + return; + } + + vty_out(vty, " IS-IS %s %s Fast ReRoute summary:\n\n", + circuit_t2string(spftree->level), tree_id_text); + + /* Prepare table. */ + tt = ttable_new(&ttable_styles[TTSTYLE_BLANK]); + ttable_add_row( + tt, + "Protection \\ Priority|Critical|High |Medium |Low |Total"); + tt->style.cell.rpad = 2; + tt->style.corner = '+'; + ttable_restyle(tt); + ttable_rowseps(tt, 0, BOTTOM, true, '-'); + + /* Compute unprotected and coverage totals. */ + for (int priority = SPF_PREFIX_PRIO_CRITICAL; + priority < SPF_PREFIX_PRIO_MAX; priority++) { + uint32_t *lfa = spftree->lfa.protection_counters.lfa; + uint32_t *rlfa = spftree->lfa.protection_counters.rlfa; + uint32_t *tilfa = spftree->lfa.protection_counters.tilfa; + uint32_t *ecmp = spftree->lfa.protection_counters.ecmp; + uint32_t *total = spftree->lfa.protection_counters.total; + + protectd[priority] = lfa[priority] + rlfa[priority] + + tilfa[priority] + ecmp[priority]; + /* Safeguard to protect against possible inconsistencies. */ + if (protectd[priority] > total[priority]) + protectd[priority] = total[priority]; + unprotected[priority] = total[priority] - protectd[priority]; + protected_total += protectd[priority]; + grand_total += total[priority]; + + if (!total[priority]) + coverage[priority] = 0; + else + coverage[priority] = + protectd[priority] / (double)total[priority]; + } + + if (!grand_total) + coverage_total = 0; + else + coverage_total = protected_total / (double)grand_total; + + /* Add rows. */ + isis_print_frr_summary_line(tt, "Classic LFA", + spftree->lfa.protection_counters.lfa); + isis_print_frr_summary_line(tt, "Remote LFA", + spftree->lfa.protection_counters.rlfa); + isis_print_frr_summary_line(tt, "Topology Independent LFA", + spftree->lfa.protection_counters.tilfa); + isis_print_frr_summary_line(tt, "ECMP", + spftree->lfa.protection_counters.ecmp); + isis_print_frr_summary_line(tt, "Unprotected", unprotected); + isis_print_frr_summary_line_coverage(tt, "Protection coverage", + coverage, coverage_total); + + /* Dump the generated table. */ + table = ttable_dump(tt, "\n"); + vty_out(vty, "%s\n", table); + XFREE(MTYPE_TMP, table); + ttable_del(tt); +} + +static void show_isis_frr_summary_common(struct vty *vty, int levels, + struct isis *isis) +{ + struct listnode *node; + struct isis_area *area; + + if (!isis->area_list || isis->area_list->count == 0) + return; + + for (ALL_LIST_ELEMENTS_RO(isis->area_list, node, area)) { + vty_out(vty, "Area %s:\n", + area->area_tag ? area->area_tag : "null"); + + for (int level = ISIS_LEVEL1; level <= ISIS_LEVELS; level++) { + if ((level & levels) == 0) + continue; + + if (area->ip_circuits > 0) { + isis_print_frr_summary( + vty, + area->spftree[SPFTREE_IPV4][level - 1]); + } + if (area->ipv6_circuits > 0) { + isis_print_frr_summary( + vty, + area->spftree[SPFTREE_IPV6][level - 1]); + } + if (isis_area_ipv6_dstsrc_enabled(area)) { + isis_print_frr_summary( + vty, area->spftree[SPFTREE_DSTSRC] + [level - 1]); + } + } + } +} + +DEFUN(show_isis_frr_summary, show_isis_frr_summary_cmd, + "show " PROTO_NAME + " [vrf <NAME|all>] fast-reroute summary" +#ifndef FABRICD + " [<level-1|level-2>]" +#endif + , + SHOW_STR PROTO_HELP VRF_FULL_CMD_HELP_STR + "IS-IS FRR information\n" + "FRR summary\n" +#ifndef FABRICD + "level-1 routes\n" + "level-2 routes\n" +#endif +) +{ + int levels; + struct isis *isis; + struct listnode *node; + const char *vrf_name = VRF_DEFAULT_NAME; + bool all_vrf = false; + int idx = 0; + + if (argv_find(argv, argc, "level-1", &idx)) + levels = ISIS_LEVEL1; + else if (argv_find(argv, argc, "level-2", &idx)) + levels = ISIS_LEVEL2; + else + levels = ISIS_LEVEL1 | ISIS_LEVEL2; + + if (!im) { + vty_out(vty, "IS-IS Routing Process not enabled\n"); + return CMD_SUCCESS; + } + ISIS_FIND_VRF_ARGS(argv, argc, idx, vrf_name, all_vrf); + + if (vrf_name) { + if (all_vrf) { + for (ALL_LIST_ELEMENTS_RO(im->isis, node, isis)) + show_isis_frr_summary_common(vty, levels, isis); + return CMD_SUCCESS; + } + isis = isis_lookup_by_vrfname(vrf_name); + if (isis != NULL) + show_isis_frr_summary_common(vty, levels, isis); + } + + return CMD_SUCCESS; +} + void isis_spf_init(void) { install_element(VIEW_NODE, &show_isis_topology_cmd); install_element(VIEW_NODE, &show_isis_route_cmd); + install_element(VIEW_NODE, &show_isis_frr_summary_cmd); /* Register hook(s). */ hook_register(isis_adj_state_change_hook, spf_adj_state_change); diff --git a/isisd/isis_spf.h b/isisd/isis_spf.h index ad15d3e3c..5b6fcdaf6 100644 --- a/isisd/isis_spf.h +++ b/isisd/isis_spf.h @@ -39,13 +39,14 @@ struct isis_spf_adj { struct isis_adjacency *adj; uint32_t metric; struct isis_ext_subtlvs *subtlvs; + struct isis_lsp *lsp; struct { uint8_t desig_is_id[ISIS_SYS_ID_LEN + 1]; - struct isis_lsp *lsp_pseudo; } lan; uint8_t flags; #define F_ISIS_SPF_ADJ_BROADCAST 0x01 #define F_ISIS_SPF_ADJ_OLDMETRIC 0x02 +#define F_ISIS_SPF_ADJ_METRIC_INFINITY 0x04 }; struct isis_spftree *isis_spftree_new(struct isis_area *area, diff --git a/isisd/isis_spf_private.h b/isisd/isis_spf_private.h index 9cb1a39b8..b7f326ca8 100644 --- a/isisd/isis_spf_private.h +++ b/isisd/isis_spf_private.h @@ -54,6 +54,7 @@ struct isis_vertex_adj { struct isis_spf_adj *sadj; struct isis_sr_psid_info sr; struct mpls_label_stack *label_stack; + uint32_t lfa_metric; }; /* @@ -66,6 +67,7 @@ struct isis_vertex { struct { struct prefix_pair p; struct isis_sr_psid_info sr; + enum spf_prefix_priority priority; } ip; } N; uint32_t d_N; /* d(N) Distance from this IS */ @@ -193,6 +195,11 @@ static void isis_vertex_del(struct isis_vertex *vertex) bool isis_vertex_adj_exists(const struct isis_spftree *spftree, const struct isis_vertex *vertex, const struct isis_spf_adj *sadj); +void isis_vertex_adj_free(void *arg); +struct isis_vertex_adj * +isis_vertex_adj_add(struct isis_spftree *spftree, struct isis_vertex *vertex, + struct list *vadj_list, struct isis_spf_adj *sadj, + struct isis_prefix_sid *psid, bool last_hop); __attribute__((__unused__)) static void isis_vertex_queue_clear(struct isis_vertex_queue *queue) @@ -341,6 +348,15 @@ struct isis_spftree { /* P-space and Q-space. */ struct isis_spf_nodes p_space; struct isis_spf_nodes q_space; + + /* Protection counters. */ + struct { + uint32_t lfa[SPF_PREFIX_PRIO_MAX]; + uint32_t rlfa[SPF_PREFIX_PRIO_MAX]; + uint32_t tilfa[SPF_PREFIX_PRIO_MAX]; + uint32_t ecmp[SPF_PREFIX_PRIO_MAX]; + uint32_t total[SPF_PREFIX_PRIO_MAX]; + } protection_counters; } lfa; uint8_t flags; }; diff --git a/isisd/isis_tlvs.h b/isisd/isis_tlvs.h index 54ded8121..037f91f0b 100644 --- a/isisd/isis_tlvs.h +++ b/isisd/isis_tlvs.h @@ -42,6 +42,9 @@ struct isis_area_address { uint8_t len; }; +#define ISIS_WIDE_METRIC_INFINITY 0xFFFFFE +#define ISIS_NARROW_METRIC_INFINITY 62 + struct isis_oldstyle_reach; struct isis_oldstyle_reach { struct isis_oldstyle_reach *next; diff --git a/isisd/isisd.c b/isisd/isisd.c index 950cdc281..827e022ba 100644 --- a/isisd/isisd.c +++ b/isisd/isisd.c @@ -31,6 +31,7 @@ #include "linklist.h" #include "if.h" #include "hash.h" +#include "filter.h" #include "stream.h" #include "prefix.h" #include "table.h" @@ -77,7 +78,7 @@ unsigned long debug_bfd; unsigned long debug_tx_queue; unsigned long debug_sr; unsigned long debug_ldp_sync; -unsigned long debug_tilfa; +unsigned long debug_lfa; DEFINE_QOBJ_TYPE(isis_area) @@ -310,6 +311,10 @@ struct isis_area *isis_area_create(const char *area_tag, const char *vrf_name) area->lsp_frag_threshold = 90; /* not currently configurable */ area->lsp_mtu = yang_get_default_uint16("/frr-isisd:isis/instance/lsp/mtu"); + area->lfa_load_sharing[0] = yang_get_default_bool( + "/frr-isisd:isis/instance/fast-reroute/level-1/lfa/load-sharing"); + area->lfa_load_sharing[1] = yang_get_default_bool( + "/frr-isisd:isis/instance/fast-reroute/level-2/lfa/load-sharing"); #else area->max_lsp_lifetime[0] = DEFAULT_LSP_LIFETIME; /* 1200 */ area->max_lsp_lifetime[1] = DEFAULT_LSP_LIFETIME; /* 1200 */ @@ -324,7 +329,13 @@ struct isis_area *isis_area_create(const char *area_tag, const char *vrf_name) area->newmetric = 1; area->lsp_frag_threshold = 90; area->lsp_mtu = DEFAULT_LSP_MTU; + area->lfa_load_sharing[0] = true; + area->lfa_load_sharing[1] = true; #endif /* ifndef FABRICD */ + area->lfa_priority_limit[0] = SPF_PREFIX_PRIO_LOW; + area->lfa_priority_limit[1] = SPF_PREFIX_PRIO_LOW; + isis_lfa_tiebreakers_init(area, ISIS_LEVEL1); + isis_lfa_tiebreakers_init(area, ISIS_LEVEL2); area_mt_init(area); @@ -461,6 +472,16 @@ void isis_area_destroy(struct isis_area *area) } area->area_addrs = NULL; + for (int i = SPF_PREFIX_PRIO_CRITICAL; i <= SPF_PREFIX_PRIO_MEDIUM; + i++) { + struct spf_prefix_priority_acl *ppa; + + ppa = &area->spf_prefix_priorities[i]; + XFREE(MTYPE_ISIS_ACL_NAME, ppa->name); + } + isis_lfa_tiebreakers_clear(area, ISIS_LEVEL1); + isis_lfa_tiebreakers_clear(area, ISIS_LEVEL2); + thread_cancel(&area->t_tick); thread_cancel(&area->t_lsp_refresh[0]); thread_cancel(&area->t_lsp_refresh[1]); @@ -605,6 +626,29 @@ void isis_terminate() isis_finish(isis); } +void isis_filter_update(struct access_list *access) +{ + 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 i = SPF_PREFIX_PRIO_CRITICAL; + i <= SPF_PREFIX_PRIO_MEDIUM; i++) { + struct spf_prefix_priority_acl *ppa; + + ppa = &area->spf_prefix_priorities[i]; + ppa->list_v4 = + access_list_lookup(AFI_IP, ppa->name); + ppa->list_v6 = + access_list_lookup(AFI_IP6, ppa->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) @@ -1199,8 +1243,8 @@ void print_debug(struct vty *vty, int flags, int onoff) if (flags & DEBUG_SR) vty_out(vty, "IS-IS Segment Routing events debugging is %s\n", onoffs); - if (flags & DEBUG_TILFA) - vty_out(vty, "IS-IS TI-LFA events debugging is %s\n", onoffs); + if (flags & DEBUG_LFA) + vty_out(vty, "IS-IS LFA events debugging is %s\n", onoffs); if (flags & DEBUG_UPDATE_PACKETS) vty_out(vty, "IS-IS Update related packet debugging is %s\n", onoffs); @@ -1295,8 +1339,8 @@ static int config_write_debug(struct vty *vty) vty_out(vty, "debug " PROTO_NAME " sr-events\n"); write++; } - if (IS_DEBUG_TILFA) { - vty_out(vty, "debug " PROTO_NAME " ti-lfa\n"); + if (IS_DEBUG_LFA) { + vty_out(vty, "debug " PROTO_NAME " lfa\n"); write++; } if (IS_DEBUG_UPDATE_PACKETS) { @@ -1529,29 +1573,29 @@ DEFUN (no_debug_isis_srevents, return CMD_SUCCESS; } -DEFUN (debug_isis_tilfa, - debug_isis_tilfa_cmd, - "debug " PROTO_NAME " ti-lfa", +DEFUN (debug_isis_lfa, + debug_isis_lfa_cmd, + "debug " PROTO_NAME " lfa", DEBUG_STR PROTO_HELP - "IS-IS TI-LFA Events\n") + "IS-IS LFA Events\n") { - debug_tilfa |= DEBUG_TILFA; - print_debug(vty, DEBUG_TILFA, 1); + debug_lfa |= DEBUG_LFA; + print_debug(vty, DEBUG_LFA, 1); return CMD_SUCCESS; } -DEFUN (no_debug_isis_tilfa, - no_debug_isis_tilfa_cmd, - "no debug " PROTO_NAME " ti-lfa", +DEFUN (no_debug_isis_lfa, + no_debug_isis_lfa_cmd, + "no debug " PROTO_NAME " lfa", NO_STR UNDEBUG_STR PROTO_HELP - "IS-IS TI-LFA Events\n") + "IS-IS LFA Events\n") { - debug_tilfa &= ~DEBUG_TILFA; - print_debug(vty, DEBUG_TILFA, 0); + debug_lfa &= ~DEBUG_LFA; + print_debug(vty, DEBUG_LFA, 0); return CMD_SUCCESS; } @@ -2892,8 +2936,8 @@ void isis_init(void) install_element(ENABLE_NODE, &no_debug_isis_spfevents_cmd); install_element(ENABLE_NODE, &debug_isis_srevents_cmd); install_element(ENABLE_NODE, &no_debug_isis_srevents_cmd); - install_element(ENABLE_NODE, &debug_isis_tilfa_cmd); - install_element(ENABLE_NODE, &no_debug_isis_tilfa_cmd); + install_element(ENABLE_NODE, &debug_isis_lfa_cmd); + install_element(ENABLE_NODE, &no_debug_isis_lfa_cmd); install_element(ENABLE_NODE, &debug_isis_rtevents_cmd); install_element(ENABLE_NODE, &no_debug_isis_rtevents_cmd); install_element(ENABLE_NODE, &debug_isis_events_cmd); @@ -2923,8 +2967,8 @@ void isis_init(void) install_element(CONFIG_NODE, &no_debug_isis_spfevents_cmd); install_element(CONFIG_NODE, &debug_isis_srevents_cmd); install_element(CONFIG_NODE, &no_debug_isis_srevents_cmd); - install_element(CONFIG_NODE, &debug_isis_tilfa_cmd); - install_element(CONFIG_NODE, &no_debug_isis_tilfa_cmd); + install_element(CONFIG_NODE, &debug_isis_lfa_cmd); + install_element(CONFIG_NODE, &no_debug_isis_lfa_cmd); install_element(CONFIG_NODE, &debug_isis_rtevents_cmd); install_element(CONFIG_NODE, &no_debug_isis_rtevents_cmd); install_element(CONFIG_NODE, &debug_isis_events_cmd); diff --git a/isisd/isisd.h b/isisd/isisd.h index 921df4d7e..4618d14af 100644 --- a/isisd/isisd.h +++ b/isisd/isisd.h @@ -33,6 +33,7 @@ #include "isisd/isis_sr.h" #include "isis_flags.h" #include "isis_lsp.h" +#include "isis_lfa.h" #include "isis_memory.h" #include "qobj.h" #include "ldp_sync.h" @@ -188,8 +189,15 @@ struct isis_area { struct isis_sr_db srdb; int ipv6_circuits; bool purge_originator; + /* SPF prefix priorities. */ + struct spf_prefix_priority_acl + spf_prefix_priorities[SPF_PREFIX_PRIO_MAX]; /* Fast Re-Route information. */ size_t lfa_protected_links[ISIS_LEVELS]; + 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]; + size_t tilfa_protected_links[ISIS_LEVELS]; /* Counters */ uint32_t circuit_state_changes; struct isis_redist redist_settings[REDIST_PROTOCOL_COUNT] @@ -231,6 +239,7 @@ struct isis_area *isis_area_lookup_by_vrf(const char *area_tag, const char *vrf_name); 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 print_debug(struct vty *, int, int); struct isis_lsp *lsp_for_arg(struct lspdb_head *head, const char *argv, struct isis *isis); @@ -280,7 +289,7 @@ extern unsigned long debug_bfd; extern unsigned long debug_tx_queue; extern unsigned long debug_sr; extern unsigned long debug_ldp_sync; -extern unsigned long debug_tilfa; +extern unsigned long debug_lfa; #define DEBUG_ADJ_PACKETS (1<<0) #define DEBUG_SNP_PACKETS (1<<1) @@ -296,7 +305,7 @@ extern unsigned long debug_tilfa; #define DEBUG_TX_QUEUE (1<<11) #define DEBUG_SR (1<<12) #define DEBUG_LDP_SYNC (1<<13) -#define DEBUG_TILFA (1<<14) +#define DEBUG_LFA (1<<14) /* Debug related macro. */ #define IS_DEBUG_ADJ_PACKETS (debug_adj_pkt & DEBUG_ADJ_PACKETS) @@ -313,7 +322,7 @@ extern unsigned long debug_tilfa; #define IS_DEBUG_TX_QUEUE (debug_tx_queue & DEBUG_TX_QUEUE) #define IS_DEBUG_SR (debug_sr & DEBUG_SR) #define IS_DEBUG_LDP_SYNC (debug_ldp_sync & DEBUG_LDP_SYNC) -#define IS_DEBUG_TILFA (debug_tilfa & DEBUG_TILFA) +#define IS_DEBUG_LFA (debug_lfa & DEBUG_LFA) #define lsp_debug(...) \ do { \ diff --git a/tests/isisd/test_isis_spf.c b/tests/isisd/test_isis_spf.c index 4c89a5be0..36ef93669 100644 --- a/tests/isisd/test_isis_spf.c +++ b/tests/isisd/test_isis_spf.c @@ -39,6 +39,7 @@ enum test_type { TEST_SPF = 1, TEST_REVERSE_SPF, + TEST_LFA, TEST_TI_LFA, }; @@ -72,6 +73,38 @@ static void test_run_spf(struct vty *vty, const struct isis_topology *topology, isis_spftree_del(spftree); } +static void test_run_lfa(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; + 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 forward SPF on all adjacent routers. */ + isis_spf_run_neighbors(spftree_self); + + /* Compute the LFA repair paths. */ + isis_lfa_compute(area, NULL, spftree_self, protected_resource); + + /* 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); +} + static void test_run_ti_lfa(struct vty *vty, const struct isis_topology *topology, const struct isis_test_node *root, @@ -120,7 +153,9 @@ static void test_run_ti_lfa(struct vty *vty, vty_out(vty, " %s\n", print_sys_hostname(node->sysid)); vty_out(vty, "\n"); - /* Print the post-convergence SPT and the correspoding routing table. */ + /* + * Print the post-convergence SPT and the corresponding routing table. + */ isis_print_spftree(vty, spftree_pc); isis_print_routes(vty, spftree_self, false, true); @@ -202,6 +237,11 @@ static int test_run(struct vty *vty, const struct isis_topology *topology, &area->lspdb[level - 1], level, tree, true); break; + case TEST_LFA: + test_run_lfa(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, @@ -221,10 +261,11 @@ static int test_run(struct vty *vty, const struct isis_topology *topology, } DEFUN(test_isis, test_isis_cmd, - "test isis topology (1-13) root HOSTNAME\ + "test isis topology (1-14) root HOSTNAME\ <\ spf\ |reverse-spf\ + |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>]", @@ -236,6 +277,11 @@ DEFUN(test_isis, test_isis_cmd, "SPF root hostname\n" "Normal Shortest Path First\n" "Reverse Shortest Path First\n" + "Classic LFA\n" + "System ID\n" + "System ID\n" + "Pseudonode-ID\n" + "Pseudonode-ID\n" "Topology Independent LFA\n" "System ID\n" "System ID\n" @@ -281,7 +327,15 @@ DEFUN(test_isis, test_isis_cmd, test_type = TEST_SPF; else if (argv_find(argv, argc, "reverse-spf", &idx)) test_type = TEST_REVERSE_SPF; - else if (argv_find(argv, argc, "ti-lfa", &idx)) { + 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, "ti-lfa", &idx)) { test_type = TEST_TI_LFA; fail_sysid_str = argv[idx + 2]->arg; @@ -404,7 +458,7 @@ int main(int argc, char **argv) listnode_add(im->isis, isis); SET_FLAG(im->options, F_ISIS_UNIT_TEST); debug_spf_events |= DEBUG_SPF_EVENTS; - debug_tilfa |= DEBUG_TILFA; + debug_lfa |= DEBUG_LFA; debug_events |= DEBUG_EVENTS; debug_rte_events |= DEBUG_RTE_EVENTS; diff --git a/tests/isisd/test_isis_spf.in b/tests/isisd/test_isis_spf.in index 6bc5442f1..93e18124e 100644 --- a/tests/isisd/test_isis_spf.in +++ b/tests/isisd/test_isis_spf.in @@ -15,6 +15,22 @@ test isis topology 13 root rt1 spf ipv4-only test isis topology 4 root rt1 reverse-spf ipv4-only test isis topology 11 root rt1 reverse-spf +test isis topology 1 root rt1 lfa system-id rt2 +test isis topology 2 root rt4 lfa system-id rt1 pseudonode-id 1 +test isis topology 2 root rt4 lfa system-id rt6 +test isis topology 3 root rt1 lfa system-id rt2 +test isis topology 3 root rt1 lfa system-id rt3 +test isis topology 7 root rt1 lfa system-id rt4 +test isis topology 7 root rt7 lfa system-id rt8 +test isis topology 7 root rt8 lfa system-id rt11 +test isis topology 9 root rt3 lfa system-id rt1 +test isis topology 10 root rt8 lfa system-id rt5 +test isis topology 11 root rt3 lfa system-id rt5 +test isis topology 13 root rt4 lfa system-id rt3 +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 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 diff --git a/tests/isisd/test_isis_spf.refout b/tests/isisd/test_isis_spf.refout index d24176a09..dced6fb10 100644 --- a/tests/isisd/test_isis_spf.refout +++ b/tests/isisd/test_isis_spf.refout @@ -721,6 +721,1092 @@ IS-IS L1 IPv6 routing table: 2001:db8::6/128 40 - rt3 16061
test#
+test# test isis topology 1 root rt1 lfa system-id rt2
+IS-IS paths to level-1 routers that speak IP
+Vertex Type Metric Next-Hop Interface Parent
+rt1
+10.0.255.1/32 IP internal 0 rt1(4)
+rt2 TE-IS 10 rt2 - rt1(4)
+rt3 TE-IS 10 rt3 - rt1(4)
+rt4 TE-IS 20 rt2 - rt2(4)
+rt5 TE-IS 20 rt3 - rt3(4)
+10.0.255.2/32 IP TE 20 rt2 - rt2(4)
+10.0.255.3/32 IP TE 20 rt3 - rt3(4)
+rt6 TE-IS 30 rt2 - rt4(4)
+ rt3 - rt5(4)
+10.0.255.4/32 IP TE 30 rt2 - rt4(4)
+10.0.255.5/32 IP TE 30 rt3 - rt5(4)
+10.0.255.6/32 IP TE 40 rt2 - rt6(4)
+ rt3 -
+
+Main:
+IS-IS L1 IPv4 routing table:
+
+ Prefix Metric Interface Nexthop Label(s)
+ ----------------------------------------------------------
+ 10.0.255.1/32 0 - - -
+ 10.0.255.2/32 20 - rt2 implicit-null
+ 10.0.255.3/32 20 - rt3 implicit-null
+ 10.0.255.4/32 30 - rt2 16040
+ 10.0.255.5/32 30 - rt3 16050
+ 10.0.255.6/32 40 - rt2 16060
+ - rt3 16060
+
+Backup:
+IS-IS L1 IPv4 routing table:
+
+IS-IS paths to level-1 routers that speak IPv6
+Vertex Type Metric Next-Hop Interface Parent
+rt1
+2001:db8::1/128 IP6 internal 0 rt1(4)
+rt2 TE-IS 10 rt2 - rt1(4)
+rt3 TE-IS 10 rt3 - rt1(4)
+rt4 TE-IS 20 rt2 - rt2(4)
+rt5 TE-IS 20 rt3 - rt3(4)
+2001:db8::2/128 IP6 internal 20 rt2 - rt2(4)
+2001:db8::3/128 IP6 internal 20 rt3 - rt3(4)
+rt6 TE-IS 30 rt2 - rt4(4)
+ rt3 - rt5(4)
+2001:db8::4/128 IP6 internal 30 rt2 - rt4(4)
+2001:db8::5/128 IP6 internal 30 rt3 - rt5(4)
+2001:db8::6/128 IP6 internal 40 rt2 - rt6(4)
+ rt3 -
+
+Main:
+IS-IS L1 IPv6 routing table:
+
+ Prefix Metric Interface Nexthop Label(s)
+ ------------------------------------------------------------
+ 2001:db8::1/128 0 - - -
+ 2001:db8::2/128 20 - rt2 implicit-null
+ 2001:db8::3/128 20 - rt3 implicit-null
+ 2001:db8::4/128 30 - rt2 16041
+ 2001:db8::5/128 30 - rt3 16051
+ 2001:db8::6/128 40 - rt2 16061
+ - rt3 16061
+
+Backup:
+IS-IS L1 IPv6 routing table:
+
+test# test isis topology 2 root rt4 lfa system-id rt1 pseudonode-id 1
+IS-IS paths to level-1 routers that speak IP
+Vertex Type Metric Next-Hop Interface Parent
+rt4
+10.0.255.4/32 IP internal 0 rt4(4)
+rt1 TE-IS 10 rt1 - rt4(4)
+rt5 TE-IS 10 rt5 - rt4(4)
+rt6 TE-IS 10 rt6 - rt4(4)
+rt1 pseudo_TE-IS 20 rt1 - rt1(4)
+ rt5 - rt5(4)
+10.0.255.1/32 IP TE 20 rt1 - rt1(4)
+10.0.255.5/32 IP TE 20 rt5 - rt5(4)
+10.0.255.6/32 IP TE 20 rt6 - rt6(4)
+rt2 TE-IS 25 rt1 - rt1(4)
+10.0.255.2/32 IP TE 35 rt1 - rt2(4)
+rt3 TE-IS 40 rt1 - rt1(4)
+10.0.255.3/32 IP TE 50 rt1 - rt3(4)
+
+Main:
+IS-IS L1 IPv4 routing table:
+
+ Prefix Metric Interface Nexthop Label(s)
+ ----------------------------------------------------------
+ 10.0.255.1/32 20 - rt1 implicit-null
+ 10.0.255.2/32 35 - rt1 16020
+ 10.0.255.3/32 50 - rt1 16030
+ 10.0.255.4/32 0 - - -
+ 10.0.255.5/32 20 - rt5 implicit-null
+ 10.0.255.6/32 20 - rt6 implicit-null
+
+Backup:
+IS-IS L1 IPv4 routing table:
+
+ Prefix Metric Interface Nexthop Label(s)
+ ----------------------------------------------------------
+ 10.0.255.2/32 40 - rt2 implicit-null
+
+IS-IS paths to level-1 routers that speak IPv6
+Vertex Type Metric Next-Hop Interface Parent
+rt4
+2001:db8::4/128 IP6 internal 0 rt4(4)
+rt1 TE-IS 10 rt1 - rt4(4)
+rt5 TE-IS 10 rt5 - rt4(4)
+rt6 TE-IS 10 rt6 - rt4(4)
+rt1 pseudo_TE-IS 20 rt1 - rt1(4)
+ rt5 - rt5(4)
+2001:db8::1/128 IP6 internal 20 rt1 - rt1(4)
+2001:db8::5/128 IP6 internal 20 rt5 - rt5(4)
+2001:db8::6/128 IP6 internal 20 rt6 - rt6(4)
+rt2 TE-IS 25 rt1 - rt1(4)
+2001:db8::2/128 IP6 internal 35 rt1 - rt2(4)
+rt3 TE-IS 40 rt1 - rt1(4)
+2001:db8::3/128 IP6 internal 50 rt1 - rt3(4)
+
+Main:
+IS-IS L1 IPv6 routing table:
+
+ Prefix Metric Interface Nexthop Label(s)
+ ------------------------------------------------------------
+ 2001:db8::1/128 20 - rt1 implicit-null
+ 2001:db8::2/128 35 - rt1 16021
+ 2001:db8::3/128 50 - rt1 16031
+ 2001:db8::4/128 0 - - -
+ 2001:db8::5/128 20 - rt5 implicit-null
+ 2001:db8::6/128 20 - rt6 implicit-null
+
+Backup:
+IS-IS L1 IPv6 routing table:
+
+ Prefix Metric Interface Nexthop Label(s)
+ ------------------------------------------------------------
+ 2001:db8::2/128 40 - rt2 implicit-null
+
+test# test isis topology 2 root rt4 lfa system-id rt6
+IS-IS paths to level-1 routers that speak IP
+Vertex Type Metric Next-Hop Interface Parent
+rt4
+10.0.255.4/32 IP internal 0 rt4(4)
+rt1 TE-IS 10 rt1 - rt4(4)
+rt5 TE-IS 10 rt5 - rt4(4)
+rt6 TE-IS 10 rt6 - rt4(4)
+rt1 pseudo_TE-IS 20 rt1 - rt1(4)
+ rt5 - rt5(4)
+10.0.255.1/32 IP TE 20 rt1 - rt1(4)
+10.0.255.5/32 IP TE 20 rt5 - rt5(4)
+10.0.255.6/32 IP TE 20 rt6 - rt6(4)
+rt2 TE-IS 25 rt1 - rt1(4)
+10.0.255.2/32 IP TE 35 rt1 - rt2(4)
+rt3 TE-IS 40 rt1 - rt1(4)
+10.0.255.3/32 IP TE 50 rt1 - rt3(4)
+
+Main:
+IS-IS L1 IPv4 routing table:
+
+ Prefix Metric Interface Nexthop Label(s)
+ ----------------------------------------------------------
+ 10.0.255.1/32 20 - rt1 implicit-null
+ 10.0.255.2/32 35 - rt1 16020
+ 10.0.255.3/32 50 - rt1 16030
+ 10.0.255.4/32 0 - - -
+ 10.0.255.5/32 20 - rt5 implicit-null
+ 10.0.255.6/32 20 - rt6 implicit-null
+
+Backup:
+IS-IS L1 IPv4 routing table:
+
+ Prefix Metric Interface Nexthop Label(s)
+ -----------------------------------------------------
+ 10.0.255.6/32 20 - rt5 16060
+
+IS-IS paths to level-1 routers that speak IPv6
+Vertex Type Metric Next-Hop Interface Parent
+rt4
+2001:db8::4/128 IP6 internal 0 rt4(4)
+rt1 TE-IS 10 rt1 - rt4(4)
+rt5 TE-IS 10 rt5 - rt4(4)
+rt6 TE-IS 10 rt6 - rt4(4)
+rt1 pseudo_TE-IS 20 rt1 - rt1(4)
+ rt5 - rt5(4)
+2001:db8::1/128 IP6 internal 20 rt1 - rt1(4)
+2001:db8::5/128 IP6 internal 20 rt5 - rt5(4)
+2001:db8::6/128 IP6 internal 20 rt6 - rt6(4)
+rt2 TE-IS 25 rt1 - rt1(4)
+2001:db8::2/128 IP6 internal 35 rt1 - rt2(4)
+rt3 TE-IS 40 rt1 - rt1(4)
+2001:db8::3/128 IP6 internal 50 rt1 - rt3(4)
+
+Main:
+IS-IS L1 IPv6 routing table:
+
+ Prefix Metric Interface Nexthop Label(s)
+ ------------------------------------------------------------
+ 2001:db8::1/128 20 - rt1 implicit-null
+ 2001:db8::2/128 35 - rt1 16021
+ 2001:db8::3/128 50 - rt1 16031
+ 2001:db8::4/128 0 - - -
+ 2001:db8::5/128 20 - rt5 implicit-null
+ 2001:db8::6/128 20 - rt6 implicit-null
+
+Backup:
+IS-IS L1 IPv6 routing table:
+
+ Prefix Metric Interface Nexthop Label(s)
+ -------------------------------------------------------
+ 2001:db8::6/128 20 - rt5 16061
+
+test# test isis topology 3 root rt1 lfa system-id rt2
+IS-IS paths to level-1 routers that speak IP
+Vertex Type Metric Next-Hop Interface Parent
+rt1
+10.0.255.1/32 IP internal 0 rt1(4)
+rt2 TE-IS 10 rt2 - rt1(4)
+rt3 TE-IS 10 rt3 - rt1(4)
+rt4 TE-IS 20 rt2 - rt2(4)
+10.0.255.2/32 IP TE 20 rt2 - rt2(4)
+10.0.255.3/32 IP TE 20 rt3 - rt3(4)
+rt5 TE-IS 30 rt2 - rt4(4)
+rt6 TE-IS 30 rt2 - rt4(4)
+10.0.255.4/32 IP TE 30 rt2 - rt4(4)
+10.0.255.5/32 IP TE 40 rt2 - rt5(4)
+10.0.255.6/32 IP TE 40 rt2 - rt6(4)
+
+Main:
+IS-IS L1 IPv4 routing table:
+
+ Prefix Metric Interface Nexthop Label(s)
+ ----------------------------------------------------------
+ 10.0.255.1/32 0 - - -
+ 10.0.255.2/32 20 - rt2 implicit-null
+ 10.0.255.3/32 20 - rt3 implicit-null
+ 10.0.255.4/32 30 - rt2 16040
+ 10.0.255.5/32 40 - rt2 16050
+ 10.0.255.6/32 40 - rt2 16060
+
+Backup:
+IS-IS L1 IPv4 routing table:
+
+ Prefix Metric Interface Nexthop Label(s)
+ -----------------------------------------------------
+ 10.0.255.2/32 20 - rt3 16020
+ 10.0.255.4/32 30 - rt3 16040
+ 10.0.255.5/32 40 - rt3 16050
+ 10.0.255.6/32 40 - rt3 16060
+
+IS-IS paths to level-1 routers that speak IPv6
+Vertex Type Metric Next-Hop Interface Parent
+rt1
+rt2 TE-IS 10 rt2 - rt1(4)
+rt3 TE-IS 10 rt3 - rt1(4)
+
+Main:
+IS-IS L1 IPv6 routing table:
+
+Backup:
+IS-IS L1 IPv6 routing table:
+
+test# test isis topology 3 root rt1 lfa system-id rt3
+IS-IS paths to level-1 routers that speak IP
+Vertex Type Metric Next-Hop Interface Parent
+rt1
+10.0.255.1/32 IP internal 0 rt1(4)
+rt2 TE-IS 10 rt2 - rt1(4)
+rt3 TE-IS 10 rt3 - rt1(4)
+rt4 TE-IS 20 rt2 - rt2(4)
+10.0.255.2/32 IP TE 20 rt2 - rt2(4)
+10.0.255.3/32 IP TE 20 rt3 - rt3(4)
+rt5 TE-IS 30 rt2 - rt4(4)
+rt6 TE-IS 30 rt2 - rt4(4)
+10.0.255.4/32 IP TE 30 rt2 - rt4(4)
+10.0.255.5/32 IP TE 40 rt2 - rt5(4)
+10.0.255.6/32 IP TE 40 rt2 - rt6(4)
+
+Main:
+IS-IS L1 IPv4 routing table:
+
+ Prefix Metric Interface Nexthop Label(s)
+ ----------------------------------------------------------
+ 10.0.255.1/32 0 - - -
+ 10.0.255.2/32 20 - rt2 implicit-null
+ 10.0.255.3/32 20 - rt3 implicit-null
+ 10.0.255.4/32 30 - rt2 16040
+ 10.0.255.5/32 40 - rt2 16050
+ 10.0.255.6/32 40 - rt2 16060
+
+Backup:
+IS-IS L1 IPv4 routing table:
+
+ Prefix Metric Interface Nexthop Label(s)
+ -----------------------------------------------------
+ 10.0.255.3/32 20 - rt2 16030
+
+IS-IS paths to level-1 routers that speak IPv6
+Vertex Type Metric Next-Hop Interface Parent
+rt1
+rt2 TE-IS 10 rt2 - rt1(4)
+rt3 TE-IS 10 rt3 - rt1(4)
+
+Main:
+IS-IS L1 IPv6 routing table:
+
+Backup:
+IS-IS L1 IPv6 routing table:
+
+test# test isis topology 7 root rt1 lfa system-id rt4
+IS-IS paths to level-1 routers that speak IP
+Vertex Type Metric Next-Hop Interface Parent
+rt1
+10.0.255.1/32 IP internal 0 rt1(4)
+rt4 TE-IS 10 rt4 - rt1(4)
+rt5 TE-IS 20 rt4 - rt4(4)
+rt7 TE-IS 20 rt4 - rt4(4)
+10.0.255.4/32 IP TE 20 rt4 - rt4(4)
+rt2 TE-IS 30 rt4 - rt5(4)
+rt6 TE-IS 30 rt4 - rt5(4)
+rt8 TE-IS 30 rt4 - rt5(4)
+ rt7(4)
+10.0.255.5/32 IP TE 30 rt4 - rt5(4)
+10.0.255.7/32 IP TE 30 rt4 - rt7(4)
+rt10 TE-IS 40 rt4 - rt7(4)
+rt3 TE-IS 40 rt4 - rt2(4)
+ rt6(4)
+rt9 TE-IS 40 rt4 - rt8(4)
+rt11 TE-IS 40 rt4 - rt8(4)
+10.0.255.2/32 IP TE 40 rt4 - rt2(4)
+10.0.255.6/32 IP TE 40 rt4 - rt6(4)
+10.0.255.8/32 IP TE 40 rt4 - rt8(4)
+rt12 TE-IS 50 rt4 - rt9(4)
+ rt11(4)
+10.0.255.10/32 IP TE 50 rt4 - rt10(4)
+10.0.255.3/32 IP TE 50 rt4 - rt3(4)
+10.0.255.9/32 IP TE 50 rt4 - rt9(4)
+10.0.255.11/32 IP TE 50 rt4 - rt11(4)
+10.0.255.12/32 IP TE 60 rt4 - rt12(4)
+
+Main:
+IS-IS L1 IPv4 routing table:
+
+ Prefix Metric Interface Nexthop Label(s)
+ -----------------------------------------------------------
+ 10.0.255.1/32 0 - - -
+ 10.0.255.2/32 40 - rt4 16020
+ 10.0.255.3/32 50 - rt4 16030
+ 10.0.255.4/32 20 - rt4 implicit-null
+ 10.0.255.5/32 30 - rt4 16050
+ 10.0.255.6/32 40 - rt4 16060
+ 10.0.255.7/32 30 - rt4 16070
+ 10.0.255.8/32 40 - rt4 16080
+ 10.0.255.9/32 50 - rt4 16090
+ 10.0.255.10/32 50 - rt4 16100
+ 10.0.255.11/32 50 - rt4 16110
+ 10.0.255.12/32 60 - rt4 16120
+
+Backup:
+IS-IS L1 IPv4 routing table:
+
+ Prefix Metric Interface Nexthop Label(s)
+ -----------------------------------------------------------
+ 10.0.255.2/32 40 - rt2 implicit-null
+ 10.0.255.3/32 50 - rt2 16030
+ 10.0.255.4/32 60 - rt2 16040
+ 10.0.255.5/32 50 - rt2 16050
+ 10.0.255.6/32 60 - rt2 16060
+ 10.0.255.7/32 70 - rt2 16070
+ 10.0.255.8/32 60 - rt2 16080
+ 10.0.255.9/32 70 - rt2 16090
+ 10.0.255.10/32 80 - rt2 16100
+ 10.0.255.11/32 70 - rt2 16110
+ 10.0.255.12/32 80 - rt2 16120
+
+IS-IS paths to level-1 routers that speak IPv6
+Vertex Type Metric Next-Hop Interface Parent
+rt1
+rt4 TE-IS 10 rt4 - rt1(4)
+rt2 TE-IS 40 rt2 - rt1(4)
+
+Main:
+IS-IS L1 IPv6 routing table:
+
+Backup:
+IS-IS L1 IPv6 routing table:
+
+test# test isis topology 7 root rt7 lfa system-id rt8
+IS-IS paths to level-1 routers that speak IP
+Vertex Type Metric Next-Hop Interface Parent
+rt7
+10.0.255.7/32 IP internal 0 rt7(4)
+rt4 TE-IS 10 rt4 - rt7(4)
+rt8 TE-IS 10 rt8 - rt7(4)
+rt10 TE-IS 20 rt10 - rt7(4)
+rt1 TE-IS 20 rt4 - rt4(4)
+rt5 TE-IS 20 rt4 - rt4(4)
+ rt8 - rt8(4)
+rt9 TE-IS 20 rt8 - rt8(4)
+rt11 TE-IS 20 rt8 - rt8(4)
+10.0.255.4/32 IP TE 20 rt4 - rt4(4)
+10.0.255.8/32 IP TE 20 rt8 - rt8(4)
+rt2 TE-IS 30 rt4 - rt5(4)
+ rt8 -
+rt6 TE-IS 30 rt4 - rt5(4)
+ rt8 -
+rt12 TE-IS 30 rt8 - rt9(4)
+ rt11(4)
+10.0.255.10/32 IP TE 30 rt10 - rt10(4)
+10.0.255.1/32 IP TE 30 rt4 - rt1(4)
+10.0.255.5/32 IP TE 30 rt4 - rt5(4)
+ rt8 -
+10.0.255.9/32 IP TE 30 rt8 - rt9(4)
+10.0.255.11/32 IP TE 30 rt8 - rt11(4)
+rt3 TE-IS 40 rt4 - rt2(4)
+ rt8 - rt6(4)
+10.0.255.2/32 IP TE 40 rt4 - rt2(4)
+ rt8 -
+10.0.255.6/32 IP TE 40 rt4 - rt6(4)
+ rt8 -
+10.0.255.12/32 IP TE 40 rt8 - rt12(4)
+10.0.255.3/32 IP TE 50 rt4 - rt3(4)
+ rt8 -
+
+Main:
+IS-IS L1 IPv4 routing table:
+
+ Prefix Metric Interface Nexthop Label(s)
+ -----------------------------------------------------------
+ 10.0.255.1/32 30 - rt4 16010
+ 10.0.255.2/32 40 - rt4 16020
+ - rt8 16020
+ 10.0.255.3/32 50 - rt4 16030
+ - rt8 16030
+ 10.0.255.4/32 20 - rt4 implicit-null
+ 10.0.255.5/32 30 - rt4 16050
+ - rt8 16050
+ 10.0.255.6/32 40 - rt4 16060
+ - rt8 16060
+ 10.0.255.7/32 0 - - -
+ 10.0.255.8/32 20 - rt8 implicit-null
+ 10.0.255.9/32 30 - rt8 16090
+ 10.0.255.10/32 30 - rt10 implicit-null
+ 10.0.255.11/32 30 - rt8 16110
+ 10.0.255.12/32 40 - rt8 16120
+
+Backup:
+IS-IS L1 IPv4 routing table:
+
+ Prefix Metric Interface Nexthop Label(s)
+ ------------------------------------------------------
+ 10.0.255.8/32 40 - rt10 16080
+ 10.0.255.9/32 50 - rt10 16090
+ 10.0.255.11/32 30 - rt10 16110
+ 10.0.255.12/32 40 - rt10 16120
+
+IS-IS paths to level-1 routers that speak IPv6
+Vertex Type Metric Next-Hop Interface Parent
+rt7
+rt4 TE-IS 10 rt4 - rt7(4)
+rt8 TE-IS 10 rt8 - rt7(4)
+rt10 TE-IS 20 rt10 - rt7(4)
+
+Main:
+IS-IS L1 IPv6 routing table:
+
+Backup:
+IS-IS L1 IPv6 routing table:
+
+test# test isis topology 7 root rt8 lfa system-id rt11
+IS-IS paths to level-1 routers that speak IP
+Vertex Type Metric Next-Hop Interface Parent
+rt8
+10.0.255.8/32 IP internal 0 rt8(4)
+rt5 TE-IS 10 rt5 - rt8(4)
+rt7 TE-IS 10 rt7 - rt8(4)
+rt9 TE-IS 10 rt9 - rt8(4)
+rt11 TE-IS 10 rt11 - rt8(4)
+rt2 TE-IS 20 rt5 - rt5(4)
+rt4 TE-IS 20 rt5 - rt5(4)
+ rt7 - rt7(4)
+rt6 TE-IS 20 rt5 - rt5(4)
+rt12 TE-IS 20 rt9 - rt9(4)
+ rt11 - rt11(4)
+rt10 TE-IS 20 rt11 - rt11(4)
+10.0.255.5/32 IP TE 20 rt5 - rt5(4)
+10.0.255.7/32 IP TE 20 rt7 - rt7(4)
+10.0.255.9/32 IP TE 20 rt9 - rt9(4)
+10.0.255.11/32 IP TE 20 rt11 - rt11(4)
+rt3 TE-IS 30 rt5 - rt2(4)
+ rt6(4)
+rt1 TE-IS 30 rt5 - rt4(4)
+ rt7 -
+10.0.255.2/32 IP TE 30 rt5 - rt2(4)
+10.0.255.4/32 IP TE 30 rt5 - rt4(4)
+ rt7 -
+10.0.255.6/32 IP TE 30 rt5 - rt6(4)
+10.0.255.12/32 IP TE 30 rt9 - rt12(4)
+ rt11 -
+10.0.255.10/32 IP TE 30 rt11 - rt10(4)
+10.0.255.3/32 IP TE 40 rt5 - rt3(4)
+10.0.255.1/32 IP TE 40 rt5 - rt1(4)
+ rt7 -
+
+Main:
+IS-IS L1 IPv4 routing table:
+
+ Prefix Metric Interface Nexthop Label(s)
+ -----------------------------------------------------------
+ 10.0.255.1/32 40 - rt5 16010
+ - rt7 16010
+ 10.0.255.2/32 30 - rt5 16020
+ 10.0.255.3/32 40 - rt5 16030
+ 10.0.255.4/32 30 - rt5 16040
+ - rt7 16040
+ 10.0.255.5/32 20 - rt5 implicit-null
+ 10.0.255.6/32 30 - rt5 16060
+ 10.0.255.7/32 20 - rt7 implicit-null
+ 10.0.255.8/32 0 - - -
+ 10.0.255.9/32 20 - rt9 implicit-null
+ 10.0.255.10/32 30 - rt11 16100
+ 10.0.255.11/32 20 - rt11 implicit-null
+ 10.0.255.12/32 30 - rt9 16120
+ - rt11 16120
+
+Backup:
+IS-IS L1 IPv4 routing table:
+
+ Prefix Metric Interface Nexthop Label(s)
+ ------------------------------------------------------
+ 10.0.255.10/32 30 - rt7 16100
+
+IS-IS paths to level-1 routers that speak IPv6
+Vertex Type Metric Next-Hop Interface Parent
+rt8
+rt5 TE-IS 10 rt5 - rt8(4)
+rt7 TE-IS 10 rt7 - rt8(4)
+rt9 TE-IS 10 rt9 - rt8(4)
+rt11 TE-IS 10 rt11 - rt8(4)
+
+Main:
+IS-IS L1 IPv6 routing table:
+
+Backup:
+IS-IS L1 IPv6 routing table:
+
+test# test isis topology 9 root rt3 lfa system-id rt1
+IS-IS paths to level-1 routers that speak IP
+Vertex Type Metric Next-Hop Interface Parent
+rt3
+10.0.255.3/32 IP internal 0 rt3(4)
+rt1 TE-IS 10 rt1 - rt3(4)
+rt2 TE-IS 20 rt1 - rt1(4)
+10.0.255.1/32 IP TE 20 rt1 - rt1(4)
+rt4 TE-IS 30 rt1 - rt2(4)
+10.0.255.2/32 IP TE 30 rt1 - rt2(4)
+rt5 TE-IS 40 rt1 - rt4(4)
+10.0.255.4/32 IP TE 40 rt1 - rt4(4)
+rt9 TE-IS 50 rt1 - rt5(4)
+10.0.255.5/32 IP TE 50 rt1 - rt5(4)
+rt6 TE-IS 60 rt1 - rt4(4)
+ rt9(4)
+rt7 TE-IS 60 rt1 - rt4(4)
+ rt9(4)
+rt8 TE-IS 60 rt1 - rt4(4)
+ rt9(4)
+10.0.255.9/32 IP TE 60 rt1 - rt9(4)
+10.0.255.6/32 IP TE 70 rt1 - rt6(4)
+10.0.255.7/32 IP TE 70 rt1 - rt7(4)
+10.0.255.8/32 IP TE 70 rt1 - rt8(4)
+
+Main:
+IS-IS L1 IPv4 routing table:
+
+ Prefix Metric Interface Nexthop Label(s)
+ ----------------------------------------------------------
+ 10.0.255.1/32 20 - rt1 implicit-null
+ 10.0.255.2/32 30 - rt1 16020
+ 10.0.255.3/32 0 - - -
+ 10.0.255.4/32 40 - rt1 16040
+ 10.0.255.5/32 50 - rt1 16050
+ 10.0.255.6/32 70 - rt1 16060
+ 10.0.255.7/32 70 - rt1 16070
+ 10.0.255.8/32 70 - rt1 16080
+ 10.0.255.9/32 60 - rt1 16090
+
+Backup:
+IS-IS L1 IPv4 routing table:
+
+ Prefix Metric Interface Nexthop Label(s)
+ ----------------------------------------------------------
+ 10.0.255.1/32 120 - rt4 16010
+ 10.0.255.2/32 110 - rt4 16020
+ 10.0.255.4/32 100 - rt4 implicit-null
+ 10.0.255.5/32 110 - rt4 16050
+ 10.0.255.6/32 130 - rt4 16060
+ 10.0.255.7/32 130 - rt4 16070
+ 10.0.255.8/32 130 - rt4 16080
+ 10.0.255.9/32 120 - rt4 16090
+
+IS-IS paths to level-1 routers that speak IPv6
+Vertex Type Metric Next-Hop Interface Parent
+rt3
+2001:db8::3/128 IP6 internal 0 rt3(4)
+rt1 TE-IS 10 rt1 - rt3(4)
+rt2 TE-IS 20 rt1 - rt1(4)
+2001:db8::1/128 IP6 internal 20 rt1 - rt1(4)
+rt4 TE-IS 30 rt1 - rt2(4)
+2001:db8::2/128 IP6 internal 30 rt1 - rt2(4)
+rt5 TE-IS 40 rt1 - rt4(4)
+2001:db8::4/128 IP6 internal 40 rt1 - rt4(4)
+rt9 TE-IS 50 rt1 - rt5(4)
+2001:db8::5/128 IP6 internal 50 rt1 - rt5(4)
+rt6 TE-IS 60 rt1 - rt4(4)
+ rt9(4)
+rt7 TE-IS 60 rt1 - rt4(4)
+ rt9(4)
+rt8 TE-IS 60 rt1 - rt4(4)
+ rt9(4)
+2001:db8::9/128 IP6 internal 60 rt1 - rt9(4)
+2001:db8::6/128 IP6 internal 70 rt1 - rt6(4)
+2001:db8::7/128 IP6 internal 70 rt1 - rt7(4)
+2001:db8::8/128 IP6 internal 70 rt1 - rt8(4)
+
+Main:
+IS-IS L1 IPv6 routing table:
+
+ Prefix Metric Interface Nexthop Label(s)
+ ------------------------------------------------------------
+ 2001:db8::1/128 20 - rt1 implicit-null
+ 2001:db8::2/128 30 - rt1 16021
+ 2001:db8::3/128 0 - - -
+ 2001:db8::4/128 40 - rt1 16041
+ 2001:db8::5/128 50 - rt1 16051
+ 2001:db8::6/128 70 - rt1 16061
+ 2001:db8::7/128 70 - rt1 16071
+ 2001:db8::8/128 70 - rt1 16081
+ 2001:db8::9/128 60 - rt1 16091
+
+Backup:
+IS-IS L1 IPv6 routing table:
+
+ Prefix Metric Interface Nexthop Label(s)
+ ------------------------------------------------------------
+ 2001:db8::1/128 120 - rt4 16011
+ 2001:db8::2/128 110 - rt4 16021
+ 2001:db8::4/128 100 - rt4 implicit-null
+ 2001:db8::5/128 110 - rt4 16051
+ 2001:db8::6/128 130 - rt4 16061
+ 2001:db8::7/128 130 - rt4 16071
+ 2001:db8::8/128 130 - rt4 16081
+ 2001:db8::9/128 120 - rt4 16091
+
+test# test isis topology 10 root rt8 lfa system-id rt5
+IS-IS paths to level-1 routers that speak IP
+Vertex Type Metric Next-Hop Interface Parent
+rt8
+10.0.255.8/32 IP internal 0 rt8(4)
+rt5 TE-IS 10 rt5 - rt8(4)
+rt2 TE-IS 20 rt5 - rt5(4)
+10.0.255.5/32 IP TE 20 rt5 - rt5(4)
+rt1 TE-IS 30 rt5 - rt2(4)
+10.0.255.2/32 IP TE 30 rt5 - rt2(4)
+10.0.255.1/32 IP TE 40 rt5 - rt1(4)
+rt6 TE-IS 50 rt6 - rt8(4)
+rt7 TE-IS 50 rt7 - rt8(4)
+rt3 TE-IS 50 rt5 - rt1(4)
+rt4 TE-IS 50 rt5 - rt1(4)
+10.0.255.6/32 IP TE 60 rt6 - rt6(4)
+10.0.255.7/32 IP TE 60 rt7 - rt7(4)
+10.0.255.3/32 IP TE 60 rt5 - rt3(4)
+10.0.255.4/32 IP TE 60 rt5 - rt4(4)
+
+Main:
+IS-IS L1 IPv4 routing table:
+
+ Prefix Metric Interface Nexthop Label(s)
+ ----------------------------------------------------------
+ 10.0.255.1/32 40 - rt5 16010
+ 10.0.255.2/32 30 - rt5 16020
+ 10.0.255.3/32 60 - rt5 16030
+ 10.0.255.4/32 60 - rt5 16040
+ 10.0.255.5/32 20 - rt5 implicit-null
+ 10.0.255.6/32 60 - rt6 implicit-null
+ 10.0.255.7/32 60 - rt7 implicit-null
+ 10.0.255.8/32 0 - - -
+
+Backup:
+IS-IS L1 IPv4 routing table:
+
+ Prefix Metric Interface Nexthop Label(s)
+ -----------------------------------------------------
+ 10.0.255.1/32 80 - rt6 16010
+ - rt7 16010
+ 10.0.255.2/32 90 - rt6 16020
+ - rt7 16020
+ 10.0.255.3/32 60 - rt6 16030
+ - rt7 16030
+ 10.0.255.4/32 60 - rt6 16040
+ - rt7 16040
+ 10.0.255.5/32 100 - rt6 16050
+ - rt7 16050
+
+IS-IS paths to level-1 routers that speak IPv6
+Vertex Type Metric Next-Hop Interface Parent
+rt8
+2001:db8::8/128 IP6 internal 0 rt8(4)
+rt5 TE-IS 10 rt5 - rt8(4)
+rt2 TE-IS 20 rt5 - rt5(4)
+2001:db8::5/128 IP6 internal 20 rt5 - rt5(4)
+rt1 TE-IS 30 rt5 - rt2(4)
+2001:db8::2/128 IP6 internal 30 rt5 - rt2(4)
+2001:db8::1/128 IP6 internal 40 rt5 - rt1(4)
+rt6 TE-IS 50 rt6 - rt8(4)
+rt7 TE-IS 50 rt7 - rt8(4)
+rt3 TE-IS 50 rt5 - rt1(4)
+rt4 TE-IS 50 rt5 - rt1(4)
+2001:db8::6/128 IP6 internal 60 rt6 - rt6(4)
+2001:db8::7/128 IP6 internal 60 rt7 - rt7(4)
+2001:db8::3/128 IP6 internal 60 rt5 - rt3(4)
+2001:db8::4/128 IP6 internal 60 rt5 - rt4(4)
+
+Main:
+IS-IS L1 IPv6 routing table:
+
+ Prefix Metric Interface Nexthop Label(s)
+ ------------------------------------------------------------
+ 2001:db8::1/128 40 - rt5 16011
+ 2001:db8::2/128 30 - rt5 16021
+ 2001:db8::3/128 60 - rt5 16031
+ 2001:db8::4/128 60 - rt5 16041
+ 2001:db8::5/128 20 - rt5 implicit-null
+ 2001:db8::6/128 60 - rt6 implicit-null
+ 2001:db8::7/128 60 - rt7 implicit-null
+ 2001:db8::8/128 0 - - -
+
+Backup:
+IS-IS L1 IPv6 routing table:
+
+ Prefix Metric Interface Nexthop Label(s)
+ -------------------------------------------------------
+ 2001:db8::1/128 80 - rt6 16011
+ - rt7 16011
+ 2001:db8::2/128 90 - rt6 16021
+ - rt7 16021
+ 2001:db8::3/128 60 - rt6 16031
+ - rt7 16031
+ 2001:db8::4/128 60 - rt6 16041
+ - rt7 16041
+ 2001:db8::5/128 100 - rt6 16051
+ - rt7 16051
+
+test# test isis topology 11 root rt3 lfa system-id rt5
+IS-IS paths to level-1 routers that speak IP
+Vertex Type Metric Next-Hop Interface Parent
+rt3
+10.0.255.3/32 IP internal 0 rt3(4)
+rt1 TE-IS 10 rt1 - rt3(4)
+rt2 TE-IS 10 rt2 - rt3(4)
+rt5 TE-IS 10 rt5 - rt3(4)
+rt2 pseudo_TE-IS 20 rt1 - rt1(4)
+rt4 TE-IS 20 rt2 - rt2(4)
+ rt5 - rt5(4)
+rt6 TE-IS 20 rt5 - rt5(4)
+10.0.255.1/32 IP TE 20 rt1 - rt1(4)
+10.0.255.2/32 IP TE 20 rt2 - rt2(4)
+10.0.255.5/32 IP TE 20 rt5 - rt5(4)
+10.0.255.4/32 IP TE 30 rt2 - rt4(4)
+ rt5 -
+10.0.255.6/32 IP TE 30 rt5 - rt6(4)
+
+Main:
+IS-IS L1 IPv4 routing table:
+
+ Prefix Metric Interface Nexthop Label(s)
+ ----------------------------------------------------------
+ 10.0.255.1/32 20 - rt1 implicit-null
+ 10.0.255.2/32 20 - rt2 implicit-null
+ 10.0.255.3/32 0 - - -
+ 10.0.255.4/32 30 - rt2 16040
+ - rt5 16040
+ 10.0.255.5/32 20 - rt5 implicit-null
+ 10.0.255.6/32 30 - rt5 16060
+
+Backup:
+IS-IS L1 IPv4 routing table:
+
+ Prefix Metric Interface Nexthop Label(s)
+ -----------------------------------------------------
+ 10.0.255.5/32 30 - rt2 16050
+ 10.0.255.6/32 30 - rt2 16060
+
+IS-IS paths to level-1 routers that speak IPv6
+Vertex Type Metric Next-Hop Interface Parent
+rt3
+2001:db8::3/128 IP6 internal 0 rt3(4)
+rt1 TE-IS 10 rt1 - rt3(4)
+rt2 TE-IS 10 rt2 - rt3(4)
+rt5 TE-IS 10 rt5 - rt3(4)
+rt2 pseudo_TE-IS 20 rt1 - rt1(4)
+rt4 TE-IS 20 rt2 - rt2(4)
+ rt5 - rt5(4)
+rt6 TE-IS 20 rt5 - rt5(4)
+2001:db8::1/128 IP6 internal 20 rt1 - rt1(4)
+2001:db8::2/128 IP6 internal 20 rt2 - rt2(4)
+2001:db8::5/128 IP6 internal 20 rt5 - rt5(4)
+2001:db8::4/128 IP6 internal 30 rt2 - rt4(4)
+ rt5 -
+2001:db8::6/128 IP6 internal 30 rt5 - rt6(4)
+
+Main:
+IS-IS L1 IPv6 routing table:
+
+ Prefix Metric Interface Nexthop Label(s)
+ ------------------------------------------------------------
+ 2001:db8::1/128 20 - rt1 implicit-null
+ 2001:db8::2/128 20 - rt2 implicit-null
+ 2001:db8::3/128 0 - - -
+ 2001:db8::4/128 30 - rt2 16041
+ - rt5 16041
+ 2001:db8::5/128 20 - rt5 implicit-null
+ 2001:db8::6/128 30 - rt5 16061
+
+Backup:
+IS-IS L1 IPv6 routing table:
+
+ Prefix Metric Interface Nexthop Label(s)
+ -------------------------------------------------------
+ 2001:db8::5/128 30 - rt2 16051
+ 2001:db8::6/128 30 - rt2 16061
+
+test# test isis topology 13 root rt4 lfa system-id rt3
+IS-IS paths to level-1 routers that speak IP
+Vertex Type Metric Next-Hop Interface Parent
+rt4
+10.0.255.4/32 IP internal 0 rt4(4)
+rt2 TE-IS 10 rt2 - rt4(4)
+rt3 TE-IS 10 rt3 - rt4(4)
+rt1 TE-IS 20 rt2 - rt2(4)
+ rt3 - rt3(4)
+rt5 TE-IS 20 rt3 - rt3(4)
+rt6 TE-IS 20 rt3 - rt3(4)
+10.0.255.2/32 IP TE 20 rt2 - rt2(4)
+10.0.255.3/32 IP TE 20 rt3 - rt3(4)
+rt7 TE-IS 30 rt3 - rt5(4)
+ rt6(4)
+10.0.255.1/32 IP TE 30 rt2 - rt1(4)
+ rt3 -
+10.0.255.5/32 IP TE 30 rt3 - rt5(4)
+10.0.255.6/32 IP TE 30 rt3 - rt6(4)
+10.0.255.7/32 IP TE 40 rt3 - rt7(4)
+
+Main:
+IS-IS L1 IPv4 routing table:
+
+ Prefix Metric Interface Nexthop Label(s)
+ ----------------------------------------------------------
+ 10.0.255.1/32 30 - rt2 16010
+ - rt3 16010
+ 10.0.255.2/32 20 - rt2 implicit-null
+ 10.0.255.3/32 20 - rt3 implicit-null
+ 10.0.255.4/32 0 - - -
+ 10.0.255.5/32 30 - rt3 16050
+ 10.0.255.6/32 30 - rt3 16060
+ 10.0.255.7/32 40 - rt3 16070
+
+Backup:
+IS-IS L1 IPv4 routing table:
+
+ Prefix Metric Interface Nexthop Label(s)
+ ----------------------------------------------------------
+ 10.0.255.3/32 110 - rt5 16030
+ 10.0.255.5/32 100 - rt5 implicit-null
+ 10.0.255.6/32 120 - rt5 16060
+ 10.0.255.7/32 110 - rt5 16070
+
+IS-IS paths to level-1 routers that speak IPv6
+Vertex Type Metric Next-Hop Interface Parent
+rt4
+rt2 TE-IS 10 rt2 - rt4(4)
+rt3 TE-IS 10 rt3 - rt4(4)
+rt5 TE-IS 100 rt5 - rt4(4)
+
+Main:
+IS-IS L1 IPv6 routing table:
+
+Backup:
+IS-IS L1 IPv6 routing table:
+
+test# test isis topology 14 root rt1 lfa system-id rt1 pseudonode-id 1
+IS-IS paths to level-1 routers that speak IP
+Vertex Type Metric Next-Hop Interface Parent
+rt1
+10.0.255.1/32 IP internal 0 rt1(4)
+rt3 TE-IS 10 rt3 - rt1(4)
+rt4 TE-IS 10 rt4 - rt1(4)
+rt2 TE-IS 10 rt2 - rt1(4)
+rt1
+rt5 TE-IS 20 rt4 - rt4(4)
+10.0.255.3/32 IP TE 20 rt3 - rt3(4)
+10.0.255.4/32 IP TE 20 rt4 - rt4(4)
+10.0.255.2/32 IP TE 20 rt2 - rt2(4)
+10.0.255.5/32 IP TE 30 rt4 - rt5(4)
+
+Main:
+IS-IS L1 IPv4 routing table:
+
+ Prefix Metric Interface Nexthop Label(s)
+ -----------------------------------------------------
+ 10.0.255.1/32 0 - - -
+ 10.0.255.2/32 20 - rt2 -
+ 10.0.255.3/32 20 - rt3 -
+ 10.0.255.4/32 20 - rt4 -
+ 10.0.255.5/32 30 - rt4 -
+
+Backup:
+IS-IS L1 IPv4 routing table:
+
+IS-IS paths to level-1 routers that speak IPv6
+Vertex Type Metric Next-Hop Interface Parent
+rt1
+2001:db8::1/128 IP6 internal 0 rt1(4)
+rt3 TE-IS 10 rt3 - rt1(4)
+rt4 TE-IS 10 rt4 - rt1(4)
+rt2 TE-IS 10 rt2 - rt1(4)
+rt1
+rt5 TE-IS 20 rt4 - rt4(4)
+2001:db8::3/128 IP6 internal 20 rt3 - rt3(4)
+2001:db8::4/128 IP6 internal 20 rt4 - rt4(4)
+2001:db8::2/128 IP6 internal 20 rt2 - rt2(4)
+2001:db8::5/128 IP6 internal 30 rt4 - rt5(4)
+
+Main:
+IS-IS L1 IPv6 routing table:
+
+ Prefix Metric Interface Nexthop Label(s)
+ -------------------------------------------------------
+ 2001:db8::1/128 0 - - -
+ 2001:db8::2/128 20 - rt2 -
+ 2001:db8::3/128 20 - rt3 -
+ 2001:db8::4/128 20 - rt4 -
+ 2001:db8::5/128 30 - rt4 -
+
+Backup:
+IS-IS L1 IPv6 routing table:
+
+test# test isis topology 14 root rt1 lfa system-id rt2
+IS-IS paths to level-1 routers that speak IP
+Vertex Type Metric Next-Hop Interface Parent
+rt1
+10.0.255.1/32 IP internal 0 rt1(4)
+rt3 TE-IS 10 rt3 - rt1(4)
+rt4 TE-IS 10 rt4 - rt1(4)
+rt2 TE-IS 10 rt2 - rt1(4)
+rt1
+rt5 TE-IS 20 rt4 - rt4(4)
+10.0.255.3/32 IP TE 20 rt3 - rt3(4)
+10.0.255.4/32 IP TE 20 rt4 - rt4(4)
+10.0.255.2/32 IP TE 20 rt2 - rt2(4)
+10.0.255.5/32 IP TE 30 rt4 - rt5(4)
+
+Main:
+IS-IS L1 IPv4 routing table:
+
+ Prefix Metric Interface Nexthop Label(s)
+ -----------------------------------------------------
+ 10.0.255.1/32 0 - - -
+ 10.0.255.2/32 20 - rt2 -
+ 10.0.255.3/32 20 - rt3 -
+ 10.0.255.4/32 20 - rt4 -
+ 10.0.255.5/32 30 - rt4 -
+
+Backup:
+IS-IS L1 IPv4 routing table:
+
+ Prefix Metric Interface Nexthop Label(s)
+ -----------------------------------------------------
+ 10.0.255.2/32 20 - rt3 -
+
+IS-IS paths to level-1 routers that speak IPv6
+Vertex Type Metric Next-Hop Interface Parent
+rt1
+2001:db8::1/128 IP6 internal 0 rt1(4)
+rt3 TE-IS 10 rt3 - rt1(4)
+rt4 TE-IS 10 rt4 - rt1(4)
+rt2 TE-IS 10 rt2 - rt1(4)
+rt1
+rt5 TE-IS 20 rt4 - rt4(4)
+2001:db8::3/128 IP6 internal 20 rt3 - rt3(4)
+2001:db8::4/128 IP6 internal 20 rt4 - rt4(4)
+2001:db8::2/128 IP6 internal 20 rt2 - rt2(4)
+2001:db8::5/128 IP6 internal 30 rt4 - rt5(4)
+
+Main:
+IS-IS L1 IPv6 routing table:
+
+ Prefix Metric Interface Nexthop Label(s)
+ -------------------------------------------------------
+ 2001:db8::1/128 0 - - -
+ 2001:db8::2/128 20 - rt2 -
+ 2001:db8::3/128 20 - rt3 -
+ 2001:db8::4/128 20 - rt4 -
+ 2001:db8::5/128 30 - rt4 -
+
+Backup:
+IS-IS L1 IPv6 routing table:
+
+ Prefix Metric Interface Nexthop Label(s)
+ -------------------------------------------------------
+ 2001:db8::2/128 20 - rt3 -
+
+test# test isis topology 14 root rt5 lfa system-id rt4
+IS-IS paths to level-1 routers that speak IP
+Vertex Type Metric Next-Hop Interface Parent
+rt5
+10.0.255.5/32 IP internal 0 rt5(4)
+rt4 TE-IS 10 rt4 - rt5(4)
+rt1 pseudo_TE-IS 20 rt4 - rt4(4)
+rt1 TE-IS 20 rt4 - rt1(2)
+rt3 TE-IS 20 rt4 - rt1(2)
+10.0.255.4/32 IP TE 20 rt4 - rt4(4)
+rt2 TE-IS 30 rt4 - rt1(4)
+ rt3(4)
+10.0.255.1/32 IP TE 30 rt4 - rt1(4)
+10.0.255.3/32 IP TE 30 rt4 - rt3(4)
+10.0.255.2/32 IP TE 40 rt4 - rt2(4)
+
+Main:
+IS-IS L1 IPv4 routing table:
+
+ Prefix Metric Interface Nexthop Label(s)
+ -----------------------------------------------------
+ 10.0.255.1/32 30 - rt4 -
+ 10.0.255.2/32 40 - rt4 -
+ 10.0.255.3/32 30 - rt4 -
+ 10.0.255.4/32 20 - rt4 -
+ 10.0.255.5/32 0 - - -
+
+Backup:
+IS-IS L1 IPv4 routing table:
+
+ Prefix Metric Interface Nexthop Label(s)
+ -----------------------------------------------------
+ 10.0.255.1/32 60 - rt3 -
+ 10.0.255.2/32 60 - rt3 -
+ 10.0.255.3/32 50 - rt3 -
+ 10.0.255.4/32 60 - rt3 -
+
+IS-IS paths to level-1 routers that speak IPv6
+Vertex Type Metric Next-Hop Interface Parent
+rt5
+2001:db8::5/128 IP6 internal 0 rt5(4)
+rt4 TE-IS 10 rt4 - rt5(4)
+rt1 pseudo_TE-IS 20 rt4 - rt4(4)
+rt1 TE-IS 20 rt4 - rt1(2)
+rt3 TE-IS 20 rt4 - rt1(2)
+2001:db8::4/128 IP6 internal 20 rt4 - rt4(4)
+rt2 TE-IS 30 rt4 - rt1(4)
+ rt3(4)
+2001:db8::1/128 IP6 internal 30 rt4 - rt1(4)
+2001:db8::3/128 IP6 internal 30 rt4 - rt3(4)
+2001:db8::2/128 IP6 internal 40 rt4 - rt2(4)
+
+Main:
+IS-IS L1 IPv6 routing table:
+
+ Prefix Metric Interface Nexthop Label(s)
+ -------------------------------------------------------
+ 2001:db8::1/128 30 - rt4 -
+ 2001:db8::2/128 40 - rt4 -
+ 2001:db8::3/128 30 - rt4 -
+ 2001:db8::4/128 20 - rt4 -
+ 2001:db8::5/128 0 - - -
+
+Backup:
+IS-IS L1 IPv6 routing table:
+
+ Prefix Metric Interface Nexthop Label(s)
+ -------------------------------------------------------
+ 2001:db8::1/128 60 - rt3 -
+ 2001:db8::2/128 60 - rt3 -
+ 2001:db8::3/128 50 - rt3 -
+ 2001:db8::4/128 60 - rt3 -
+
+test#
test# test isis topology 1 root rt1 ti-lfa system-id rt2
P-space (self):
rt3
diff --git a/tests/isisd/test_topologies.c b/tests/isisd/test_topologies.c index ee89407a7..ca103948f 100644 --- a/tests/isisd/test_topologies.c +++ b/tests/isisd/test_topologies.c @@ -531,6 +531,34 @@ * | +---------------------+ | * | | | | * +---------+ +---------+ + + * Test topology 14: + * ================= + * + * +---------+ +---------+ + * | | | | + * | RT1 | | RT2 | + * | +--------------+ | + * | | | | + * +----+----+ +----+----+ + * | | + * | | + * | | + * | +----+----+ + * | | | + * | | RT3 | + * +-------------------+ | + * | | | + * | +----+----+ + * | | + * | |50 + * | | + * +----+----+ +----+----+ + * | | | | + * | RT4 | | RT5 | + * | +--------------+ | + * | | | | + * +---------+ +---------+ */ struct isis_topology test_topologies[] = { @@ -3302,6 +3330,158 @@ struct isis_topology test_topologies[] = { }, }, { + .number = 14, + .nodes = { + { + .hostname = "rt1", + .sysid = {0x00, 0x00, 0x00, 0x00, 0x00, 0x01}, + .level = IS_LEVEL_1, + .router_id = "10.0.255.1", + .protocols = { + .ipv4 = true, + .ipv6 = true, + }, + .networks = { + "10.0.255.1/32", + "2001:db8::1/128", + }, + .adjacencies = { + { + .hostname = "rt1", + .pseudonode_id = 1, + .metric = 10, + }, + { + .hostname = "rt2", + .metric = 10, + }, + }, + }, + { + .hostname = "rt2", + .sysid = {0x00, 0x00, 0x00, 0x00, 0x00, 0x02}, + .level = IS_LEVEL_1, + .router_id = "10.0.255.2", + .protocols = { + .ipv4 = true, + .ipv6 = true, + }, + .networks = { + "10.0.255.2/32", + "2001:db8::2/128", + }, + .adjacencies = { + { + .hostname = "rt1", + .metric = 20, + }, + { + .hostname = "rt3", + .metric = 10, + }, + }, + }, + { + .hostname = "rt3", + .sysid = {0x00, 0x00, 0x00, 0x00, 0x00, 0x03}, + .level = IS_LEVEL_1, + .router_id = "10.0.255.3", + .protocols = { + .ipv4 = true, + .ipv6 = true, + }, + .networks = { + "10.0.255.3/32", + "2001:db8::3/128", + }, + .adjacencies = { + { + .hostname = "rt1", + .pseudonode_id = 1, + .metric = 10, + }, + { + .hostname = "rt2", + .metric = 10, + }, + { + .hostname = "rt5", + .metric = 50, + }, + }, + }, + { + .hostname = "rt4", + .sysid = {0x00, 0x00, 0x00, 0x00, 0x00, 0x04}, + .level = IS_LEVEL_1, + .router_id = "10.0.255.4", + .protocols = { + .ipv4 = true, + .ipv6 = true, + }, + .networks = { + "10.0.255.4/32", + "2001:db8::4/128", + }, + .adjacencies = { + { + .hostname = "rt1", + .pseudonode_id = 1, + .metric = 10, + }, + { + .hostname = "rt5", + .metric = 10, + }, + }, + }, + { + .hostname = "rt5", + .sysid = {0x00, 0x00, 0x00, 0x00, 0x00, 0x05}, + .level = IS_LEVEL_1, + .router_id = "10.0.255.5", + .protocols = { + .ipv4 = true, + .ipv6 = true, + }, + .networks = { + "10.0.255.5/32", + "2001:db8::5/128", + }, + .adjacencies = { + { + .hostname = "rt4", + .metric = 10, + }, + { + .hostname = "rt3", + .metric = 50, + }, + }, + }, + { + .hostname = "rt1", + .sysid = {0x00, 0x00, 0x00, 0x00, 0x00, 0x01}, + .pseudonode_id = 1, + .level = IS_LEVEL_1, + .adjacencies = { + { + .hostname = "rt1", + .metric = 0, + }, + { + .hostname = "rt3", + .metric = 0, + }, + { + .hostname = "rt4", + .metric = 0, + }, + }, + }, + }, + }, + { /* sentinel */ }, }; diff --git a/tests/topotests/isis-lfa-topo1/__init__.py b/tests/topotests/isis-lfa-topo1/__init__.py new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/tests/topotests/isis-lfa-topo1/__init__.py diff --git a/tests/topotests/isis-lfa-topo1/rt1/isisd.conf b/tests/topotests/isis-lfa-topo1/rt1/isisd.conf new file mode 100644 index 000000000..2ad8c1253 --- /dev/null +++ b/tests/topotests/isis-lfa-topo1/rt1/isisd.conf @@ -0,0 +1,52 @@ +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 + ipv6 router isis 1 + isis passive +! +interface eth-rt2 + ipv6 router isis 1 + isis network point-to-point + isis hello-multiplier 3 + isis fast-reroute lfa +! +interface eth-rt3 + ipv6 router isis 1 + isis network point-to-point + isis hello-multiplier 3 + isis fast-reroute lfa +! +interface eth-rt4 + ipv6 router isis 1 + isis network point-to-point + isis hello-multiplier 3 + isis fast-reroute lfa +! +interface eth-rt5 + ipv6 router isis 1 + isis metric 20 + isis network point-to-point + isis hello-multiplier 3 + isis fast-reroute lfa +! +interface eth-rt6 + ipv6 router isis 1 + isis network point-to-point + isis hello-multiplier 3 + isis fast-reroute lfa +! +router isis 1 + net 49.0000.0000.0000.0001.00 + is-type level-1 + lsp-gen-interval 2 + topology ipv6-unicast + !fast-reroute lfa tiebreaker node-protecting index 10 + !fast-reroute lfa tiebreaker downstream index 20 + !fast-reroute lfa tiebreaker lowest-backup-metric index 30 diff --git a/tests/topotests/isis-lfa-topo1/rt1/step1/show_ipv6_route.ref b/tests/topotests/isis-lfa-topo1/rt1/step1/show_ipv6_route.ref new file mode 100644 index 000000000..10c61d53e --- /dev/null +++ b/tests/topotests/isis-lfa-topo1/rt1/step1/show_ipv6_route.ref @@ -0,0 +1,236 @@ +{ + "2001:db8:1000::2\/128":[ + { + "prefix":"2001:db8:1000::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, + 1, + 2 + ] + } + ], + "backupNexthops":[ + { + "afi":"ipv6", + "interfaceName":"eth-rt3", + "active":true + }, + { + "afi":"ipv6", + "interfaceName":"eth-rt5", + "active":true + }, + { + "afi":"ipv6", + "interfaceName":"eth-rt6", + "active":true + } + ] + } + ], + "2001:db8:1000::3\/128":[ + { + "prefix":"2001:db8:1000::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, + 1 + ] + } + ], + "backupNexthops":[ + { + "afi":"ipv6", + "interfaceName":"eth-rt2", + "active":true + }, + { + "afi":"ipv6", + "interfaceName":"eth-rt5", + "active":true + } + ] + } + ], + "2001:db8:1000::4\/128":[ + { + "prefix":"2001:db8:1000::4\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt4", + "active":true, + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "afi":"ipv6", + "interfaceName":"eth-rt5", + "active":true + } + ] + } + ], + "2001:db8:1000::5\/128":[ + { + "prefix":"2001:db8:1000::5\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt5", + "active":true, + "backupIndex":[ + 0, + 1, + 2, + 3 + ] + } + ], + "backupNexthops":[ + { + "afi":"ipv6", + "interfaceName":"eth-rt2", + "active":true + }, + { + "afi":"ipv6", + "interfaceName":"eth-rt3", + "active":true + }, + { + "afi":"ipv6", + "interfaceName":"eth-rt4", + "active":true + }, + { + "afi":"ipv6", + "interfaceName":"eth-rt6", + "active":true + } + ] + } + ], + "2001:db8:1000::6\/128":[ + { + "prefix":"2001:db8:1000::6\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt6", + "active":true, + "backupIndex":[ + 0, + 1 + ] + } + ], + "backupNexthops":[ + { + "afi":"ipv6", + "interfaceName":"eth-rt2", + "active":true + }, + { + "afi":"ipv6", + "interfaceName":"eth-rt5", + "active":true + } + ] + } + ], + "2001:db8:1000::7\/128":[ + { + "prefix":"2001:db8:1000::7\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":25, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt2", + "active":true, + "backupIndex":[ + 0, + 1, + 2, + 3 + ] + } + ], + "backupNexthops":[ + { + "afi":"ipv6", + "interfaceName":"eth-rt3", + "active":true + }, + { + "afi":"ipv6", + "interfaceName":"eth-rt4", + "active":true + }, + { + "afi":"ipv6", + "interfaceName":"eth-rt5", + "active":true + }, + { + "afi":"ipv6", + "interfaceName":"eth-rt6", + "active":true + } + ] + } + ] +} diff --git a/tests/topotests/isis-lfa-topo1/rt1/step1/show_yang_interface_isis_adjacencies.ref b/tests/topotests/isis-lfa-topo1/rt1/step1/show_yang_interface_isis_adjacencies.ref new file mode 100644 index 000000000..d8a7c5a9c --- /dev/null +++ b/tests/topotests/isis-lfa-topo1/rt1/step1/show_yang_interface_isis_adjacencies.ref @@ -0,0 +1,101 @@ +{ + "frr-interface:lib": { + "interface": [ + { + "name": "eth-rt2", + "vrf": "default", + "state": { + "frr-isisd:isis": { + "adjacencies": { + "adjacency": [ + { + "neighbor-sys-type": "level-1", + "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", + "neighbor-sysid": "0000.0000.0003", + "hold-timer": 9, + "neighbor-priority": 0, + "state": "up" + } + ] + } + } + } + }, + { + "name": "eth-rt4", + "vrf": "default", + "state": { + "frr-isisd:isis": { + "adjacencies": { + "adjacency": [ + { + "neighbor-sys-type": "level-1", + "neighbor-sysid": "0000.0000.0004", + "hold-timer": 9, + "neighbor-priority": 0, + "state": "up" + } + ] + } + } + } + }, + { + "name": "eth-rt5", + "vrf": "default", + "state": { + "frr-isisd:isis": { + "adjacencies": { + "adjacency": [ + { + "neighbor-sys-type": "level-1", + "neighbor-sysid": "0000.0000.0005", + "hold-timer": 9, + "neighbor-priority": 0, + "state": "up" + } + ] + } + } + } + }, + { + "name": "eth-rt6", + "vrf": "default", + "state": { + "frr-isisd:isis": { + "adjacencies": { + "adjacency": [ + { + "neighbor-sys-type": "level-1", + "neighbor-sysid": "0000.0000.0006", + "hold-timer": 9, + "neighbor-priority": 0, + "state": "up" + } + ] + } + } + } + } + ] + } +} diff --git a/tests/topotests/isis-lfa-topo1/rt1/step10/show_ipv6_route.ref.diff b/tests/topotests/isis-lfa-topo1/rt1/step10/show_ipv6_route.ref.diff new file mode 100644 index 000000000..d626cdca0 --- /dev/null +++ b/tests/topotests/isis-lfa-topo1/rt1/step10/show_ipv6_route.ref.diff @@ -0,0 +1,46 @@ +--- a/rt1/step9/show_ipv6_route.ref ++++ b/rt1/step10/show_ipv6_route.ref +@@ -16,7 +16,8 @@ + "active":true, + "backupIndex":[ + 0, +- 1 ++ 1, ++ 2 + ] + } + ], +@@ -30,6 +31,11 @@ + "afi":"ipv6", + "interfaceName":"eth-rt5", + "active":true ++ }, ++ { ++ "afi":"ipv6", ++ "interfaceName":"eth-rt6", ++ "active":true + } + ] + } +@@ -198,7 +204,8 @@ + "backupIndex":[ + 0, + 1, +- 2 ++ 2, ++ 3 + ] + } + ], +@@ -217,6 +224,11 @@ + "afi":"ipv6", + "interfaceName":"eth-rt5", + "active":true ++ }, ++ { ++ "afi":"ipv6", ++ "interfaceName":"eth-rt6", ++ "active":true + } + ] + } diff --git a/tests/topotests/isis-lfa-topo1/rt1/step11/show_ipv6_route.ref.diff b/tests/topotests/isis-lfa-topo1/rt1/step11/show_ipv6_route.ref.diff new file mode 100644 index 000000000..f7f99c276 --- /dev/null +++ b/tests/topotests/isis-lfa-topo1/rt1/step11/show_ipv6_route.ref.diff @@ -0,0 +1,23 @@ +--- a/rt1/step10/show_ipv6_route.ref ++++ b/rt1/step11/show_ipv6_route.ref +@@ -204,19 +204,13 @@ + "backupIndex":[ + 0, + 1, +- 2, +- 3 ++ 2 + ] + } + ], + "backupNexthops":[ + { + "afi":"ipv6", +- "interfaceName":"eth-rt3", +- "active":true +- }, +- { +- "afi":"ipv6", + "interfaceName":"eth-rt4", + "active":true + }, diff --git a/tests/topotests/isis-lfa-topo1/rt1/step12/show_ipv6_route.ref.diff b/tests/topotests/isis-lfa-topo1/rt1/step12/show_ipv6_route.ref.diff new file mode 100644 index 000000000..3b767f1bf --- /dev/null +++ b/tests/topotests/isis-lfa-topo1/rt1/step12/show_ipv6_route.ref.diff @@ -0,0 +1,107 @@ +--- a/rt1/step11/show_ipv6_route.ref ++++ b/rt1/step12/show_ipv6_route.ref +@@ -15,9 +15,7 @@ + "interfaceName":"eth-rt2", + "active":true, + "backupIndex":[ +- 0, +- 1, +- 2 ++ 0 + ] + } + ], +@@ -26,16 +24,6 @@ + "afi":"ipv6", + "interfaceName":"eth-rt3", + "active":true +- }, +- { +- "afi":"ipv6", +- "interfaceName":"eth-rt5", +- "active":true +- }, +- { +- "afi":"ipv6", +- "interfaceName":"eth-rt6", +- "active":true + } + ] + } +@@ -56,8 +44,7 @@ + "interfaceName":"eth-rt3", + "active":true, + "backupIndex":[ +- 0, +- 1 ++ 0 + ] + } + ], +@@ -66,11 +53,6 @@ + "afi":"ipv6", + "interfaceName":"eth-rt2", + "active":true +- }, +- { +- "afi":"ipv6", +- "interfaceName":"eth-rt5", +- "active":true + } + ] + } +@@ -120,10 +102,7 @@ + "interfaceName":"eth-rt5", + "active":true, + "backupIndex":[ +- 0, +- 1, +- 2, +- 3 ++ 0 + ] + } + ], +@@ -132,21 +111,6 @@ + "afi":"ipv6", + "interfaceName":"eth-rt2", + "active":true +- }, +- { +- "afi":"ipv6", +- "interfaceName":"eth-rt3", +- "active":true +- }, +- { +- "afi":"ipv6", +- "interfaceName":"eth-rt4", +- "active":true +- }, +- { +- "afi":"ipv6", +- "interfaceName":"eth-rt6", +- "active":true + } + ] + } +@@ -203,19 +167,13 @@ + "active":true, + "backupIndex":[ + 0, +- 1, +- 2 ++ 1 + ] + } + ], + "backupNexthops":[ + { + "afi":"ipv6", +- "interfaceName":"eth-rt4", +- "active":true +- }, +- { +- "afi":"ipv6", + "interfaceName":"eth-rt5", + "active":true + }, diff --git a/tests/topotests/isis-lfa-topo1/rt1/step13/show_ipv6_route.ref.diff b/tests/topotests/isis-lfa-topo1/rt1/step13/show_ipv6_route.ref.diff new file mode 100644 index 000000000..504af5ac5 --- /dev/null +++ b/tests/topotests/isis-lfa-topo1/rt1/step13/show_ipv6_route.ref.diff @@ -0,0 +1,45 @@ +--- a/rt1/step12/show_ipv6_route.ref ++++ b/rt1/step13/show_ipv6_route.ref +@@ -131,8 +131,7 @@ + "interfaceName":"eth-rt6", + "active":true, + "backupIndex":[ +- 0, +- 1 ++ 0 + ] + } + ], +@@ -141,11 +140,6 @@ + "afi":"ipv6", + "interfaceName":"eth-rt2", + "active":true +- }, +- { +- "afi":"ipv6", +- "interfaceName":"eth-rt5", +- "active":true + } + ] + } +@@ -166,19 +160,13 @@ + "interfaceName":"eth-rt2", + "active":true, + "backupIndex":[ +- 0, +- 1 ++ 0 + ] + } + ], + "backupNexthops":[ + { + "afi":"ipv6", +- "interfaceName":"eth-rt5", +- "active":true +- }, +- { +- "afi":"ipv6", + "interfaceName":"eth-rt6", + "active":true + } diff --git a/tests/topotests/isis-lfa-topo1/rt1/step2/show_ipv6_route.ref.diff b/tests/topotests/isis-lfa-topo1/rt1/step2/show_ipv6_route.ref.diff new file mode 100644 index 000000000..efc56d983 --- /dev/null +++ b/tests/topotests/isis-lfa-topo1/rt1/step2/show_ipv6_route.ref.diff @@ -0,0 +1,164 @@ +--- a/rt1/step1/show_ipv6_route.ref ++++ b/rt1/step2/show_ipv6_route.ref +@@ -13,28 +13,6 @@ + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt2", +- "active":true, +- "backupIndex":[ +- 0, +- 1, +- 2 +- ] +- } +- ], +- "backupNexthops":[ +- { +- "afi":"ipv6", +- "interfaceName":"eth-rt3", +- "active":true +- }, +- { +- "afi":"ipv6", +- "interfaceName":"eth-rt5", +- "active":true +- }, +- { +- "afi":"ipv6", +- "interfaceName":"eth-rt6", + "active":true + } + ] +@@ -54,22 +32,6 @@ + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt3", +- "active":true, +- "backupIndex":[ +- 0, +- 1 +- ] +- } +- ], +- "backupNexthops":[ +- { +- "afi":"ipv6", +- "interfaceName":"eth-rt2", +- "active":true +- }, +- { +- "afi":"ipv6", +- "interfaceName":"eth-rt5", + "active":true + } + ] +@@ -89,16 +51,6 @@ + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt4", +- "active":true, +- "backupIndex":[ +- 0 +- ] +- } +- ], +- "backupNexthops":[ +- { +- "afi":"ipv6", +- "interfaceName":"eth-rt5", + "active":true + } + ] +@@ -118,34 +70,6 @@ + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt5", +- "active":true, +- "backupIndex":[ +- 0, +- 1, +- 2, +- 3 +- ] +- } +- ], +- "backupNexthops":[ +- { +- "afi":"ipv6", +- "interfaceName":"eth-rt2", +- "active":true +- }, +- { +- "afi":"ipv6", +- "interfaceName":"eth-rt3", +- "active":true +- }, +- { +- "afi":"ipv6", +- "interfaceName":"eth-rt4", +- "active":true +- }, +- { +- "afi":"ipv6", +- "interfaceName":"eth-rt6", + "active":true + } + ] +@@ -165,22 +89,6 @@ + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt6", +- "active":true, +- "backupIndex":[ +- 0, +- 1 +- ] +- } +- ], +- "backupNexthops":[ +- { +- "afi":"ipv6", +- "interfaceName":"eth-rt2", +- "active":true +- }, +- { +- "afi":"ipv6", +- "interfaceName":"eth-rt5", + "active":true + } + ] +@@ -200,34 +108,6 @@ + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt2", +- "active":true, +- "backupIndex":[ +- 0, +- 1, +- 2, +- 3 +- ] +- } +- ], +- "backupNexthops":[ +- { +- "afi":"ipv6", +- "interfaceName":"eth-rt3", +- "active":true +- }, +- { +- "afi":"ipv6", +- "interfaceName":"eth-rt4", +- "active":true +- }, +- { +- "afi":"ipv6", +- "interfaceName":"eth-rt5", +- "active":true +- }, +- { +- "afi":"ipv6", +- "interfaceName":"eth-rt6", + "active":true + } + ] diff --git a/tests/topotests/isis-lfa-topo1/rt1/step3/show_ipv6_route.ref.diff b/tests/topotests/isis-lfa-topo1/rt1/step3/show_ipv6_route.ref.diff new file mode 100644 index 000000000..cafbe490b --- /dev/null +++ b/tests/topotests/isis-lfa-topo1/rt1/step3/show_ipv6_route.ref.diff @@ -0,0 +1,164 @@ +--- a/rt1/step2/show_ipv6_route.ref ++++ b/rt1/step3/show_ipv6_route.ref +@@ -13,6 +13,28 @@ + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt2", ++ "active":true, ++ "backupIndex":[ ++ 0, ++ 1, ++ 2 ++ ] ++ } ++ ], ++ "backupNexthops":[ ++ { ++ "afi":"ipv6", ++ "interfaceName":"eth-rt3", ++ "active":true ++ }, ++ { ++ "afi":"ipv6", ++ "interfaceName":"eth-rt5", ++ "active":true ++ }, ++ { ++ "afi":"ipv6", ++ "interfaceName":"eth-rt6", + "active":true + } + ] +@@ -32,6 +54,22 @@ + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt3", ++ "active":true, ++ "backupIndex":[ ++ 0, ++ 1 ++ ] ++ } ++ ], ++ "backupNexthops":[ ++ { ++ "afi":"ipv6", ++ "interfaceName":"eth-rt2", ++ "active":true ++ }, ++ { ++ "afi":"ipv6", ++ "interfaceName":"eth-rt5", + "active":true + } + ] +@@ -51,6 +89,16 @@ + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt4", ++ "active":true, ++ "backupIndex":[ ++ 0 ++ ] ++ } ++ ], ++ "backupNexthops":[ ++ { ++ "afi":"ipv6", ++ "interfaceName":"eth-rt5", + "active":true + } + ] +@@ -70,6 +118,34 @@ + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt5", ++ "active":true, ++ "backupIndex":[ ++ 0, ++ 1, ++ 2, ++ 3 ++ ] ++ } ++ ], ++ "backupNexthops":[ ++ { ++ "afi":"ipv6", ++ "interfaceName":"eth-rt2", ++ "active":true ++ }, ++ { ++ "afi":"ipv6", ++ "interfaceName":"eth-rt3", ++ "active":true ++ }, ++ { ++ "afi":"ipv6", ++ "interfaceName":"eth-rt4", ++ "active":true ++ }, ++ { ++ "afi":"ipv6", ++ "interfaceName":"eth-rt6", + "active":true + } + ] +@@ -89,6 +165,22 @@ + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt6", ++ "active":true, ++ "backupIndex":[ ++ 0, ++ 1 ++ ] ++ } ++ ], ++ "backupNexthops":[ ++ { ++ "afi":"ipv6", ++ "interfaceName":"eth-rt2", ++ "active":true ++ }, ++ { ++ "afi":"ipv6", ++ "interfaceName":"eth-rt5", + "active":true + } + ] +@@ -108,6 +200,34 @@ + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt2", ++ "active":true, ++ "backupIndex":[ ++ 0, ++ 1, ++ 2, ++ 3 ++ ] ++ } ++ ], ++ "backupNexthops":[ ++ { ++ "afi":"ipv6", ++ "interfaceName":"eth-rt3", ++ "active":true ++ }, ++ { ++ "afi":"ipv6", ++ "interfaceName":"eth-rt4", ++ "active":true ++ }, ++ { ++ "afi":"ipv6", ++ "interfaceName":"eth-rt5", ++ "active":true ++ }, ++ { ++ "afi":"ipv6", ++ "interfaceName":"eth-rt6", + "active":true + } + ] diff --git a/tests/topotests/isis-lfa-topo1/rt1/step4/show_ipv6_route.ref.diff b/tests/topotests/isis-lfa-topo1/rt1/step4/show_ipv6_route.ref.diff new file mode 100644 index 000000000..47d8334a0 --- /dev/null +++ b/tests/topotests/isis-lfa-topo1/rt1/step4/show_ipv6_route.ref.diff @@ -0,0 +1,142 @@ +--- a/rt1/step3/show_ipv6_route.ref ++++ b/rt1/step4/show_ipv6_route.ref +@@ -15,9 +15,7 @@ + "interfaceName":"eth-rt2", + "active":true, + "backupIndex":[ +- 0, +- 1, +- 2 ++ 0 + ] + } + ], +@@ -26,16 +24,6 @@ + "afi":"ipv6", + "interfaceName":"eth-rt3", + "active":true +- }, +- { +- "afi":"ipv6", +- "interfaceName":"eth-rt5", +- "active":true +- }, +- { +- "afi":"ipv6", +- "interfaceName":"eth-rt6", +- "active":true + } + ] + } +@@ -56,8 +44,7 @@ + "interfaceName":"eth-rt3", + "active":true, + "backupIndex":[ +- 0, +- 1 ++ 0 + ] + } + ], +@@ -66,11 +53,6 @@ + "afi":"ipv6", + "interfaceName":"eth-rt2", + "active":true +- }, +- { +- "afi":"ipv6", +- "interfaceName":"eth-rt5", +- "active":true + } + ] + } +@@ -120,10 +102,7 @@ + "interfaceName":"eth-rt5", + "active":true, + "backupIndex":[ +- 0, +- 1, +- 2, +- 3 ++ 0 + ] + } + ], +@@ -132,21 +111,6 @@ + "afi":"ipv6", + "interfaceName":"eth-rt2", + "active":true +- }, +- { +- "afi":"ipv6", +- "interfaceName":"eth-rt3", +- "active":true +- }, +- { +- "afi":"ipv6", +- "interfaceName":"eth-rt4", +- "active":true +- }, +- { +- "afi":"ipv6", +- "interfaceName":"eth-rt6", +- "active":true + } + ] + } +@@ -167,8 +131,7 @@ + "interfaceName":"eth-rt6", + "active":true, + "backupIndex":[ +- 0, +- 1 ++ 0 + ] + } + ], +@@ -177,11 +140,6 @@ + "afi":"ipv6", + "interfaceName":"eth-rt2", + "active":true +- }, +- { +- "afi":"ipv6", +- "interfaceName":"eth-rt5", +- "active":true + } + ] + } +@@ -202,10 +160,7 @@ + "interfaceName":"eth-rt2", + "active":true, + "backupIndex":[ +- 0, +- 1, +- 2, +- 3 ++ 0 + ] + } + ], +@@ -214,21 +169,6 @@ + "afi":"ipv6", + "interfaceName":"eth-rt3", + "active":true +- }, +- { +- "afi":"ipv6", +- "interfaceName":"eth-rt4", +- "active":true +- }, +- { +- "afi":"ipv6", +- "interfaceName":"eth-rt5", +- "active":true +- }, +- { +- "afi":"ipv6", +- "interfaceName":"eth-rt6", +- "active":true + } + ] + } diff --git a/tests/topotests/isis-lfa-topo1/rt1/step5/show_ipv6_route.ref.diff b/tests/topotests/isis-lfa-topo1/rt1/step5/show_ipv6_route.ref.diff new file mode 100644 index 000000000..b6a342df8 --- /dev/null +++ b/tests/topotests/isis-lfa-topo1/rt1/step5/show_ipv6_route.ref.diff @@ -0,0 +1,142 @@ +--- a/rt1/step4/show_ipv6_route.ref ++++ b/rt1/step5/show_ipv6_route.ref +@@ -15,7 +15,9 @@ + "interfaceName":"eth-rt2", + "active":true, + "backupIndex":[ +- 0 ++ 0, ++ 1, ++ 2 + ] + } + ], +@@ -24,6 +26,16 @@ + "afi":"ipv6", + "interfaceName":"eth-rt3", + "active":true ++ }, ++ { ++ "afi":"ipv6", ++ "interfaceName":"eth-rt5", ++ "active":true ++ }, ++ { ++ "afi":"ipv6", ++ "interfaceName":"eth-rt6", ++ "active":true + } + ] + } +@@ -44,7 +56,8 @@ + "interfaceName":"eth-rt3", + "active":true, + "backupIndex":[ +- 0 ++ 0, ++ 1 + ] + } + ], +@@ -53,6 +66,11 @@ + "afi":"ipv6", + "interfaceName":"eth-rt2", + "active":true ++ }, ++ { ++ "afi":"ipv6", ++ "interfaceName":"eth-rt5", ++ "active":true + } + ] + } +@@ -102,7 +120,10 @@ + "interfaceName":"eth-rt5", + "active":true, + "backupIndex":[ +- 0 ++ 0, ++ 1, ++ 2, ++ 3 + ] + } + ], +@@ -111,6 +132,21 @@ + "afi":"ipv6", + "interfaceName":"eth-rt2", + "active":true ++ }, ++ { ++ "afi":"ipv6", ++ "interfaceName":"eth-rt3", ++ "active":true ++ }, ++ { ++ "afi":"ipv6", ++ "interfaceName":"eth-rt4", ++ "active":true ++ }, ++ { ++ "afi":"ipv6", ++ "interfaceName":"eth-rt6", ++ "active":true + } + ] + } +@@ -131,7 +167,8 @@ + "interfaceName":"eth-rt6", + "active":true, + "backupIndex":[ +- 0 ++ 0, ++ 1 + ] + } + ], +@@ -140,6 +177,11 @@ + "afi":"ipv6", + "interfaceName":"eth-rt2", + "active":true ++ }, ++ { ++ "afi":"ipv6", ++ "interfaceName":"eth-rt5", ++ "active":true + } + ] + } +@@ -160,7 +202,10 @@ + "interfaceName":"eth-rt2", + "active":true, + "backupIndex":[ +- 0 ++ 0, ++ 1, ++ 2, ++ 3 + ] + } + ], +@@ -169,6 +214,21 @@ + "afi":"ipv6", + "interfaceName":"eth-rt3", + "active":true ++ }, ++ { ++ "afi":"ipv6", ++ "interfaceName":"eth-rt4", ++ "active":true ++ }, ++ { ++ "afi":"ipv6", ++ "interfaceName":"eth-rt5", ++ "active":true ++ }, ++ { ++ "afi":"ipv6", ++ "interfaceName":"eth-rt6", ++ "active":true + } + ] + } diff --git a/tests/topotests/isis-lfa-topo1/rt1/step6/show_ipv6_route.ref.diff b/tests/topotests/isis-lfa-topo1/rt1/step6/show_ipv6_route.ref.diff new file mode 100644 index 000000000..fafa2999d --- /dev/null +++ b/tests/topotests/isis-lfa-topo1/rt1/step6/show_ipv6_route.ref.diff @@ -0,0 +1,164 @@ +--- a/rt1/step5/show_ipv6_route.ref ++++ b/rt1/step6/show_ipv6_route.ref +@@ -13,28 +13,6 @@ + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt2", +- "active":true, +- "backupIndex":[ +- 0, +- 1, +- 2 +- ] +- } +- ], +- "backupNexthops":[ +- { +- "afi":"ipv6", +- "interfaceName":"eth-rt3", +- "active":true +- }, +- { +- "afi":"ipv6", +- "interfaceName":"eth-rt5", +- "active":true +- }, +- { +- "afi":"ipv6", +- "interfaceName":"eth-rt6", + "active":true + } + ] +@@ -54,22 +32,6 @@ + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt3", +- "active":true, +- "backupIndex":[ +- 0, +- 1 +- ] +- } +- ], +- "backupNexthops":[ +- { +- "afi":"ipv6", +- "interfaceName":"eth-rt2", +- "active":true +- }, +- { +- "afi":"ipv6", +- "interfaceName":"eth-rt5", + "active":true + } + ] +@@ -89,16 +51,6 @@ + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt4", +- "active":true, +- "backupIndex":[ +- 0 +- ] +- } +- ], +- "backupNexthops":[ +- { +- "afi":"ipv6", +- "interfaceName":"eth-rt5", + "active":true + } + ] +@@ -118,34 +70,6 @@ + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt5", +- "active":true, +- "backupIndex":[ +- 0, +- 1, +- 2, +- 3 +- ] +- } +- ], +- "backupNexthops":[ +- { +- "afi":"ipv6", +- "interfaceName":"eth-rt2", +- "active":true +- }, +- { +- "afi":"ipv6", +- "interfaceName":"eth-rt3", +- "active":true +- }, +- { +- "afi":"ipv6", +- "interfaceName":"eth-rt4", +- "active":true +- }, +- { +- "afi":"ipv6", +- "interfaceName":"eth-rt6", + "active":true + } + ] +@@ -165,22 +89,6 @@ + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt6", +- "active":true, +- "backupIndex":[ +- 0, +- 1 +- ] +- } +- ], +- "backupNexthops":[ +- { +- "afi":"ipv6", +- "interfaceName":"eth-rt2", +- "active":true +- }, +- { +- "afi":"ipv6", +- "interfaceName":"eth-rt5", + "active":true + } + ] +@@ -200,34 +108,6 @@ + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt2", +- "active":true, +- "backupIndex":[ +- 0, +- 1, +- 2, +- 3 +- ] +- } +- ], +- "backupNexthops":[ +- { +- "afi":"ipv6", +- "interfaceName":"eth-rt3", +- "active":true +- }, +- { +- "afi":"ipv6", +- "interfaceName":"eth-rt4", +- "active":true +- }, +- { +- "afi":"ipv6", +- "interfaceName":"eth-rt5", +- "active":true +- }, +- { +- "afi":"ipv6", +- "interfaceName":"eth-rt6", + "active":true + } + ] diff --git a/tests/topotests/isis-lfa-topo1/rt1/step7/show_ipv6_route.ref.diff b/tests/topotests/isis-lfa-topo1/rt1/step7/show_ipv6_route.ref.diff new file mode 100644 index 000000000..1803e2cf5 --- /dev/null +++ b/tests/topotests/isis-lfa-topo1/rt1/step7/show_ipv6_route.ref.diff @@ -0,0 +1,37 @@ +--- a/rt1/step6/show_ipv6_route.ref ++++ b/rt1/step7/show_ipv6_route.ref +@@ -108,6 +108,34 @@ + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt2", ++ "active":true, ++ "backupIndex":[ ++ 0, ++ 1, ++ 2, ++ 3 ++ ] ++ } ++ ], ++ "backupNexthops":[ ++ { ++ "afi":"ipv6", ++ "interfaceName":"eth-rt3", ++ "active":true ++ }, ++ { ++ "afi":"ipv6", ++ "interfaceName":"eth-rt4", ++ "active":true ++ }, ++ { ++ "afi":"ipv6", ++ "interfaceName":"eth-rt5", ++ "active":true ++ }, ++ { ++ "afi":"ipv6", ++ "interfaceName":"eth-rt6", + "active":true + } + ] diff --git a/tests/topotests/isis-lfa-topo1/rt1/step8/show_ipv6_route.ref.diff b/tests/topotests/isis-lfa-topo1/rt1/step8/show_ipv6_route.ref.diff new file mode 100644 index 000000000..306f72534 --- /dev/null +++ b/tests/topotests/isis-lfa-topo1/rt1/step8/show_ipv6_route.ref.diff @@ -0,0 +1,129 @@ +--- a/rt1/step7/show_ipv6_route.ref ++++ b/rt1/step8/show_ipv6_route.ref +@@ -13,6 +13,28 @@ + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt2", ++ "active":true, ++ "backupIndex":[ ++ 0, ++ 1, ++ 2 ++ ] ++ } ++ ], ++ "backupNexthops":[ ++ { ++ "afi":"ipv6", ++ "interfaceName":"eth-rt3", ++ "active":true ++ }, ++ { ++ "afi":"ipv6", ++ "interfaceName":"eth-rt5", ++ "active":true ++ }, ++ { ++ "afi":"ipv6", ++ "interfaceName":"eth-rt6", + "active":true + } + ] +@@ -32,6 +54,22 @@ + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt3", ++ "active":true, ++ "backupIndex":[ ++ 0, ++ 1 ++ ] ++ } ++ ], ++ "backupNexthops":[ ++ { ++ "afi":"ipv6", ++ "interfaceName":"eth-rt2", ++ "active":true ++ }, ++ { ++ "afi":"ipv6", ++ "interfaceName":"eth-rt5", + "active":true + } + ] +@@ -51,6 +89,16 @@ + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt4", ++ "active":true, ++ "backupIndex":[ ++ 0 ++ ] ++ } ++ ], ++ "backupNexthops":[ ++ { ++ "afi":"ipv6", ++ "interfaceName":"eth-rt5", + "active":true + } + ] +@@ -70,6 +118,34 @@ + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt5", ++ "active":true, ++ "backupIndex":[ ++ 0, ++ 1, ++ 2, ++ 3 ++ ] ++ } ++ ], ++ "backupNexthops":[ ++ { ++ "afi":"ipv6", ++ "interfaceName":"eth-rt2", ++ "active":true ++ }, ++ { ++ "afi":"ipv6", ++ "interfaceName":"eth-rt3", ++ "active":true ++ }, ++ { ++ "afi":"ipv6", ++ "interfaceName":"eth-rt4", ++ "active":true ++ }, ++ { ++ "afi":"ipv6", ++ "interfaceName":"eth-rt6", + "active":true + } + ] +@@ -89,6 +165,22 @@ + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt6", ++ "active":true, ++ "backupIndex":[ ++ 0, ++ 1 ++ ] ++ } ++ ], ++ "backupNexthops":[ ++ { ++ "afi":"ipv6", ++ "interfaceName":"eth-rt2", ++ "active":true ++ }, ++ { ++ "afi":"ipv6", ++ "interfaceName":"eth-rt5", + "active":true + } + ] diff --git a/tests/topotests/isis-lfa-topo1/rt1/step9/show_ipv6_route.ref.diff b/tests/topotests/isis-lfa-topo1/rt1/step9/show_ipv6_route.ref.diff new file mode 100644 index 000000000..3ffab46ee --- /dev/null +++ b/tests/topotests/isis-lfa-topo1/rt1/step9/show_ipv6_route.ref.diff @@ -0,0 +1,46 @@ +--- a/rt1/step8/show_ipv6_route.ref ++++ b/rt1/step9/show_ipv6_route.ref +@@ -16,8 +16,7 @@ + "active":true, + "backupIndex":[ + 0, +- 1, +- 2 ++ 1 + ] + } + ], +@@ -31,11 +30,6 @@ + "afi":"ipv6", + "interfaceName":"eth-rt5", + "active":true +- }, +- { +- "afi":"ipv6", +- "interfaceName":"eth-rt6", +- "active":true + } + ] + } +@@ -204,8 +198,7 @@ + "backupIndex":[ + 0, + 1, +- 2, +- 3 ++ 2 + ] + } + ], +@@ -224,11 +217,6 @@ + "afi":"ipv6", + "interfaceName":"eth-rt5", + "active":true +- }, +- { +- "afi":"ipv6", +- "interfaceName":"eth-rt6", +- "active":true + } + ] + } diff --git a/tests/topotests/isis-lfa-topo1/rt1/zebra.conf b/tests/topotests/isis-lfa-topo1/rt1/zebra.conf new file mode 100644 index 000000000..317f1031d --- /dev/null +++ b/tests/topotests/isis-lfa-topo1/rt1/zebra.conf @@ -0,0 +1,16 @@ +log file zebra.log +! +hostname rt1 +! +debug zebra kernel +debug zebra packet +debug zebra mpls +! +interface lo + ip address 1.1.1.1/32 + ipv6 address 2001:db8:1000::1/128 +! +ip forwarding +! +line vty +! diff --git a/tests/topotests/isis-lfa-topo1/rt2/isisd.conf b/tests/topotests/isis-lfa-topo1/rt2/isisd.conf new file mode 100644 index 000000000..39ff2570d --- /dev/null +++ b/tests/topotests/isis-lfa-topo1/rt2/isisd.conf @@ -0,0 +1,39 @@ +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 + ipv6 router isis 1 + isis passive +! +interface eth-rt1 + ipv6 router isis 1 + isis network point-to-point + isis hello-multiplier 3 + isis fast-reroute lfa +! +interface eth-rt3 + ipv6 router isis 1 + isis metric 5 + isis network point-to-point + isis hello-multiplier 3 + isis fast-reroute lfa +! +interface eth-rt7 + ipv6 router isis 1 + isis metric 5 + isis network point-to-point + isis hello-multiplier 3 + isis fast-reroute lfa +! +router isis 1 + net 49.0000.0000.0000.0002.00 + is-type level-1 + lsp-gen-interval 2 + topology ipv6-unicast +! diff --git a/tests/topotests/isis-lfa-topo1/rt2/step1/show_ipv6_route.ref b/tests/topotests/isis-lfa-topo1/rt2/step1/show_ipv6_route.ref new file mode 100644 index 000000000..036bfe1f4 --- /dev/null +++ b/tests/topotests/isis-lfa-topo1/rt2/step1/show_ipv6_route.ref @@ -0,0 +1,162 @@ +{ + "2001:db8:1000::1\/128":[ + { + "prefix":"2001:db8:1000::1\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt1", + "active":true, + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "afi":"ipv6", + "interfaceName":"eth-rt3", + "active":true + } + ] + } + ], + "2001:db8:1000::3\/128":[ + { + "prefix":"2001:db8:1000::3\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":15, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt3", + "active":true, + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "afi":"ipv6", + "interfaceName":"eth-rt1", + "active":true + } + ] + } + ], + "2001:db8:1000::4\/128":[ + { + "prefix":"2001:db8:1000::4\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt1", + "active":true + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt7", + "active":true + } + ] + } + ], + "2001:db8:1000::5\/128":[ + { + "prefix":"2001:db8:1000::5\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":25, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt7", + "active":true, + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "afi":"ipv6", + "interfaceName":"eth-rt1", + "active":true + } + ] + } + ], + "2001:db8:1000::6\/128":[ + { + "prefix":"2001:db8:1000::6\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":25, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt7", + "active":true, + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "afi":"ipv6", + "interfaceName":"eth-rt1", + "active":true + } + ] + } + ], + "2001:db8:1000::7\/128":[ + { + "prefix":"2001:db8:1000::7\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":15, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt7", + "active":true + } + ] + } + ] +} diff --git a/tests/topotests/isis-lfa-topo1/rt2/step1/show_yang_interface_isis_adjacencies.ref b/tests/topotests/isis-lfa-topo1/rt2/step1/show_yang_interface_isis_adjacencies.ref new file mode 100644 index 000000000..681c5222a --- /dev/null +++ b/tests/topotests/isis-lfa-topo1/rt2/step1/show_yang_interface_isis_adjacencies.ref @@ -0,0 +1,63 @@ +{ + "frr-interface:lib": { + "interface": [ + { + "name": "eth-rt1", + "vrf": "default", + "state": { + "frr-isisd:isis": { + "adjacencies": { + "adjacency": [ + { + "neighbor-sys-type": "level-1", + "neighbor-sysid": "0000.0000.0001", + "hold-timer": 9, + "neighbor-priority": 0, + "state": "up" + } + ] + } + } + } + }, + { + "name": "eth-rt3", + "vrf": "default", + "state": { + "frr-isisd:isis": { + "adjacencies": { + "adjacency": [ + { + "neighbor-sys-type": "level-1", + "neighbor-sysid": "0000.0000.0003", + "hold-timer": 9, + "neighbor-priority": 0, + "state": "up" + } + ] + } + } + } + }, + { + "name": "eth-rt7", + "vrf": "default", + "state": { + "frr-isisd:isis": { + "adjacencies": { + "adjacency": [ + { + "neighbor-sys-type": "level-1", + "neighbor-sysid": "0000.0000.0007", + "hold-timer": 9, + "neighbor-priority": 0, + "state": "up" + } + ] + } + } + } + } + ] + } +} diff --git a/tests/topotests/isis-lfa-topo1/rt2/zebra.conf b/tests/topotests/isis-lfa-topo1/rt2/zebra.conf new file mode 100644 index 000000000..9feaada79 --- /dev/null +++ b/tests/topotests/isis-lfa-topo1/rt2/zebra.conf @@ -0,0 +1,16 @@ +log file zebra.log +! +hostname rt2 +! +debug zebra kernel +debug zebra packet +debug zebra mpls +! +interface lo + ip address 2.2.2.2/32 + ipv6 address 2001:db8:1000::2/128 +! +ip forwarding +! +line vty +! diff --git a/tests/topotests/isis-lfa-topo1/rt3/isisd.conf b/tests/topotests/isis-lfa-topo1/rt3/isisd.conf new file mode 100644 index 000000000..8b0c7bd0d --- /dev/null +++ b/tests/topotests/isis-lfa-topo1/rt3/isisd.conf @@ -0,0 +1,38 @@ +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 + ipv6 router isis 1 + isis passive +! +interface eth-rt1 + ipv6 router isis 1 + isis network point-to-point + isis hello-multiplier 3 + isis fast-reroute lfa +! +interface eth-rt2 + ipv6 router isis 1 + isis metric 5 + isis network point-to-point + isis hello-multiplier 3 + isis fast-reroute lfa +! +interface eth-rt7 + ipv6 router isis 1 + isis network point-to-point + isis hello-multiplier 3 + isis fast-reroute lfa +! +router isis 1 + net 49.0000.0000.0000.0003.00 + is-type level-1 + lsp-gen-interval 2 + topology ipv6-unicast +! diff --git a/tests/topotests/isis-lfa-topo1/rt3/step1/show_ipv6_route.ref b/tests/topotests/isis-lfa-topo1/rt3/step1/show_ipv6_route.ref new file mode 100644 index 000000000..a1aab400e --- /dev/null +++ b/tests/topotests/isis-lfa-topo1/rt3/step1/show_ipv6_route.ref @@ -0,0 +1,188 @@ +{ + "2001:db8:1000::1\/128":[ + { + "prefix":"2001:db8:1000::1\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt1", + "active":true, + "backupIndex":[ + 0, + 1 + ] + } + ], + "backupNexthops":[ + { + "afi":"ipv6", + "interfaceName":"eth-rt2", + "active":true + }, + { + "afi":"ipv6", + "interfaceName":"eth-rt7", + "active":true + } + ] + } + ], + "2001:db8:1000::2\/128":[ + { + "prefix":"2001:db8:1000::2\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":15, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt2", + "active":true, + "backupIndex":[ + 0, + 1 + ] + } + ], + "backupNexthops":[ + { + "afi":"ipv6", + "interfaceName":"eth-rt1", + "active":true + }, + { + "afi":"ipv6", + "interfaceName":"eth-rt7", + "active":true + } + ] + } + ], + "2001:db8:1000::4\/128":[ + { + "prefix":"2001:db8:1000::4\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt1", + "active":true, + "backupIndex":[ + 0, + 1 + ] + } + ], + "backupNexthops":[ + { + "afi":"ipv6", + "interfaceName":"eth-rt2", + "active":true + }, + { + "afi":"ipv6", + "interfaceName":"eth-rt7", + "active":true + } + ] + } + ], + "2001:db8:1000::5\/128":[ + { + "prefix":"2001:db8:1000::5\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt2", + "active":true + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt7", + "active":true + } + ] + } + ], + "2001:db8:1000::6\/128":[ + { + "prefix":"2001:db8:1000::6\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt2", + "active":true + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt1", + "active":true + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt7", + "active":true + } + ] + } + ], + "2001:db8:1000::7\/128":[ + { + "prefix":"2001:db8:1000::7\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt2", + "active":true + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt7", + "active":true + } + ] + } + ] +} diff --git a/tests/topotests/isis-lfa-topo1/rt3/step1/show_yang_interface_isis_adjacencies.ref b/tests/topotests/isis-lfa-topo1/rt3/step1/show_yang_interface_isis_adjacencies.ref new file mode 100644 index 000000000..1495e3228 --- /dev/null +++ b/tests/topotests/isis-lfa-topo1/rt3/step1/show_yang_interface_isis_adjacencies.ref @@ -0,0 +1,63 @@ +{ + "frr-interface:lib": { + "interface": [ + { + "name": "eth-rt1", + "vrf": "default", + "state": { + "frr-isisd:isis": { + "adjacencies": { + "adjacency": [ + { + "neighbor-sys-type": "level-1", + "neighbor-sysid": "0000.0000.0001", + "hold-timer": 9, + "neighbor-priority": 0, + "state": "up" + } + ] + } + } + } + }, + { + "name": "eth-rt2", + "vrf": "default", + "state": { + "frr-isisd:isis": { + "adjacencies": { + "adjacency": [ + { + "neighbor-sys-type": "level-1", + "neighbor-sysid": "0000.0000.0002", + "hold-timer": 9, + "neighbor-priority": 0, + "state": "up" + } + ] + } + } + } + }, + { + "name": "eth-rt7", + "vrf": "default", + "state": { + "frr-isisd:isis": { + "adjacencies": { + "adjacency": [ + { + "neighbor-sys-type": "level-1", + "neighbor-sysid": "0000.0000.0007", + "hold-timer": 9, + "neighbor-priority": 0, + "state": "up" + } + ] + } + } + } + } + ] + } +} diff --git a/tests/topotests/isis-lfa-topo1/rt3/zebra.conf b/tests/topotests/isis-lfa-topo1/rt3/zebra.conf new file mode 100644 index 000000000..48d732e72 --- /dev/null +++ b/tests/topotests/isis-lfa-topo1/rt3/zebra.conf @@ -0,0 +1,16 @@ +log file zebra.log +! +hostname rt3 +! +debug zebra kernel +debug zebra packet +debug zebra mpls +! +interface lo + ip address 3.3.3.3/32 + ipv6 address 2001:db8:1000::3/128 +! +ip forwarding +! +line vty +! diff --git a/tests/topotests/isis-lfa-topo1/rt4/isisd.conf b/tests/topotests/isis-lfa-topo1/rt4/isisd.conf new file mode 100644 index 000000000..86edee6ab --- /dev/null +++ b/tests/topotests/isis-lfa-topo1/rt4/isisd.conf @@ -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 + ipv6 router isis 1 + isis passive +! +interface eth-rt1 + ipv6 router isis 1 + isis network point-to-point + isis hello-multiplier 3 + isis fast-reroute lfa +! +interface eth-rt7 + ipv6 router isis 1 + isis metric 15 + isis network point-to-point + isis hello-multiplier 3 + isis fast-reroute lfa +! +router isis 1 + net 49.0000.0000.0000.0004.00 + is-type level-1 + lsp-gen-interval 2 + topology ipv6-unicast +! diff --git a/tests/topotests/isis-lfa-topo1/rt4/step1/show_ipv6_route.ref b/tests/topotests/isis-lfa-topo1/rt4/step1/show_ipv6_route.ref new file mode 100644 index 000000000..6878e2fac --- /dev/null +++ b/tests/topotests/isis-lfa-topo1/rt4/step1/show_ipv6_route.ref @@ -0,0 +1,172 @@ +{ + "2001:db8:1000::1\/128":[ + { + "prefix":"2001:db8:1000::1\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt1", + "active":true, + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "afi":"ipv6", + "interfaceName":"eth-rt7", + "active":true + } + ] + } + ], + "2001:db8:1000::2\/128":[ + { + "prefix":"2001:db8:1000::2\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt7", + "active":true + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt1", + "active":true + } + ] + } + ], + "2001:db8:1000::3\/128":[ + { + "prefix":"2001:db8:1000::3\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt1", + "active":true, + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "afi":"ipv6", + "interfaceName":"eth-rt7", + "active":true + } + ] + } + ], + "2001:db8:1000::5\/128":[ + { + "prefix":"2001:db8:1000::5\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":35, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt7", + "active":true, + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "afi":"ipv6", + "interfaceName":"eth-rt1", + "active":true + } + ] + } + ], + "2001:db8:1000::6\/128":[ + { + "prefix":"2001:db8:1000::6\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt1", + "active":true, + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "afi":"ipv6", + "interfaceName":"eth-rt7", + "active":true + } + ] + } + ], + "2001:db8:1000::7\/128":[ + { + "prefix":"2001:db8:1000::7\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":25, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt7", + "active":true, + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "afi":"ipv6", + "interfaceName":"eth-rt1", + "active":true + } + ] + } + ] +} diff --git a/tests/topotests/isis-lfa-topo1/rt4/step1/show_yang_interface_isis_adjacencies.ref b/tests/topotests/isis-lfa-topo1/rt4/step1/show_yang_interface_isis_adjacencies.ref new file mode 100644 index 000000000..d8cd565b5 --- /dev/null +++ b/tests/topotests/isis-lfa-topo1/rt4/step1/show_yang_interface_isis_adjacencies.ref @@ -0,0 +1,44 @@ +{ + "frr-interface:lib": { + "interface": [ + { + "name": "eth-rt1", + "vrf": "default", + "state": { + "frr-isisd:isis": { + "adjacencies": { + "adjacency": [ + { + "neighbor-sys-type": "level-1", + "neighbor-sysid": "0000.0000.0001", + "hold-timer": 9, + "neighbor-priority": 0, + "state": "up" + } + ] + } + } + } + }, + { + "name": "eth-rt7", + "vrf": "default", + "state": { + "frr-isisd:isis": { + "adjacencies": { + "adjacency": [ + { + "neighbor-sys-type": "level-1", + "neighbor-sysid": "0000.0000.0007", + "hold-timer": 9, + "neighbor-priority": 0, + "state": "up" + } + ] + } + } + } + } + ] + } +} diff --git a/tests/topotests/isis-lfa-topo1/rt4/zebra.conf b/tests/topotests/isis-lfa-topo1/rt4/zebra.conf new file mode 100644 index 000000000..bff10860c --- /dev/null +++ b/tests/topotests/isis-lfa-topo1/rt4/zebra.conf @@ -0,0 +1,16 @@ +log file zebra.log +! +hostname rt4 +! +debug zebra kernel +debug zebra packet +debug zebra mpls +! +interface lo + ip address 4.4.4.4/32 + ipv6 address 2001:db8:1000::4/128 +! +ip forwarding +! +line vty +! diff --git a/tests/topotests/isis-lfa-topo1/rt5/isisd.conf b/tests/topotests/isis-lfa-topo1/rt5/isisd.conf new file mode 100644 index 000000000..7a7cfe557 --- /dev/null +++ b/tests/topotests/isis-lfa-topo1/rt5/isisd.conf @@ -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 + ipv6 router isis 1 + isis passive +! +interface eth-rt1 + ipv6 router isis 1 + isis metric 20 + isis network point-to-point + isis hello-multiplier 3 + isis fast-reroute lfa +! +interface eth-rt7 + ipv6 router isis 1 + isis network point-to-point + isis hello-multiplier 3 + isis fast-reroute lfa +! +router isis 1 + net 49.0000.0000.0000.0005.00 + is-type level-1 + lsp-gen-interval 2 + topology ipv6-unicast +! diff --git a/tests/topotests/isis-lfa-topo1/rt5/step1/show_ipv6_route.ref b/tests/topotests/isis-lfa-topo1/rt5/step1/show_ipv6_route.ref new file mode 100644 index 000000000..f8181c776 --- /dev/null +++ b/tests/topotests/isis-lfa-topo1/rt5/step1/show_ipv6_route.ref @@ -0,0 +1,176 @@ +{ + "2001:db8:1000::1\/128":[ + { + "prefix":"2001:db8:1000::1\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt1", + "active":true, + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "afi":"ipv6", + "interfaceName":"eth-rt7", + "active":true + } + ] + } + ], + "2001:db8:1000::2\/128":[ + { + "prefix":"2001:db8:1000::2\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":25, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt7", + "active":true, + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "afi":"ipv6", + "interfaceName":"eth-rt1", + "active":true + } + ] + } + ], + "2001:db8:1000::3\/128":[ + { + "prefix":"2001:db8:1000::3\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt7", + "active":true, + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "afi":"ipv6", + "interfaceName":"eth-rt1", + "active":true + } + ] + } + ], + "2001:db8:1000::4\/128":[ + { + "prefix":"2001:db8:1000::4\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":35, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt7", + "active":true, + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "afi":"ipv6", + "interfaceName":"eth-rt1", + "active":true + } + ] + } + ], + "2001:db8:1000::6\/128":[ + { + "prefix":"2001:db8:1000::6\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt7", + "active":true, + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "afi":"ipv6", + "interfaceName":"eth-rt1", + "active":true + } + ] + } + ], + "2001:db8:1000::7\/128":[ + { + "prefix":"2001:db8:1000::7\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt7", + "active":true, + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "afi":"ipv6", + "interfaceName":"eth-rt1", + "active":true + } + ] + } + ] +} diff --git a/tests/topotests/isis-lfa-topo1/rt5/step1/show_yang_interface_isis_adjacencies.ref b/tests/topotests/isis-lfa-topo1/rt5/step1/show_yang_interface_isis_adjacencies.ref new file mode 100644 index 000000000..d8cd565b5 --- /dev/null +++ b/tests/topotests/isis-lfa-topo1/rt5/step1/show_yang_interface_isis_adjacencies.ref @@ -0,0 +1,44 @@ +{ + "frr-interface:lib": { + "interface": [ + { + "name": "eth-rt1", + "vrf": "default", + "state": { + "frr-isisd:isis": { + "adjacencies": { + "adjacency": [ + { + "neighbor-sys-type": "level-1", + "neighbor-sysid": "0000.0000.0001", + "hold-timer": 9, + "neighbor-priority": 0, + "state": "up" + } + ] + } + } + } + }, + { + "name": "eth-rt7", + "vrf": "default", + "state": { + "frr-isisd:isis": { + "adjacencies": { + "adjacency": [ + { + "neighbor-sys-type": "level-1", + "neighbor-sysid": "0000.0000.0007", + "hold-timer": 9, + "neighbor-priority": 0, + "state": "up" + } + ] + } + } + } + } + ] + } +} diff --git a/tests/topotests/isis-lfa-topo1/rt5/zebra.conf b/tests/topotests/isis-lfa-topo1/rt5/zebra.conf new file mode 100644 index 000000000..ee1e46c96 --- /dev/null +++ b/tests/topotests/isis-lfa-topo1/rt5/zebra.conf @@ -0,0 +1,16 @@ +log file zebra.log +! +hostname rt5 +! +debug zebra kernel +debug zebra packet +debug zebra mpls +! +interface lo + ip address 5.5.5.5/32 + ipv6 address 2001:db8:1000::5/128 +! +ip forwarding +! +line vty +! diff --git a/tests/topotests/isis-lfa-topo1/rt6/isisd.conf b/tests/topotests/isis-lfa-topo1/rt6/isisd.conf new file mode 100644 index 000000000..20cb7769a --- /dev/null +++ b/tests/topotests/isis-lfa-topo1/rt6/isisd.conf @@ -0,0 +1,31 @@ +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 + ipv6 router isis 1 + isis passive +! +interface eth-rt1 + ipv6 router isis 1 + isis network point-to-point + isis hello-multiplier 3 + isis fast-reroute lfa +! +interface eth-rt7 + ipv6 router isis 1 + isis network point-to-point + isis hello-multiplier 3 + isis fast-reroute lfa +! +router isis 1 + net 49.0000.0000.0000.0006.00 + is-type level-1 + lsp-gen-interval 2 + topology ipv6-unicast +! diff --git a/tests/topotests/isis-lfa-topo1/rt6/step1/show_ipv6_route.ref b/tests/topotests/isis-lfa-topo1/rt6/step1/show_ipv6_route.ref new file mode 100644 index 000000000..e5f3c77ac --- /dev/null +++ b/tests/topotests/isis-lfa-topo1/rt6/step1/show_ipv6_route.ref @@ -0,0 +1,172 @@ +{ + "2001:db8:1000::1\/128":[ + { + "prefix":"2001:db8:1000::1\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt1", + "active":true, + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "afi":"ipv6", + "interfaceName":"eth-rt7", + "active":true + } + ] + } + ], + "2001:db8:1000::2\/128":[ + { + "prefix":"2001:db8:1000::2\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":25, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt7", + "active":true, + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "afi":"ipv6", + "interfaceName":"eth-rt1", + "active":true + } + ] + } + ], + "2001:db8:1000::3\/128":[ + { + "prefix":"2001:db8:1000::3\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt1", + "active":true + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt7", + "active":true + } + ] + } + ], + "2001:db8:1000::4\/128":[ + { + "prefix":"2001:db8:1000::4\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt1", + "active":true, + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "afi":"ipv6", + "interfaceName":"eth-rt7", + "active":true + } + ] + } + ], + "2001:db8:1000::5\/128":[ + { + "prefix":"2001:db8:1000::5\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt7", + "active":true, + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "afi":"ipv6", + "interfaceName":"eth-rt1", + "active":true + } + ] + } + ], + "2001:db8:1000::7\/128":[ + { + "prefix":"2001:db8:1000::7\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt7", + "active":true, + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "afi":"ipv6", + "interfaceName":"eth-rt1", + "active":true + } + ] + } + ] +} diff --git a/tests/topotests/isis-lfa-topo1/rt6/step1/show_yang_interface_isis_adjacencies.ref b/tests/topotests/isis-lfa-topo1/rt6/step1/show_yang_interface_isis_adjacencies.ref new file mode 100644 index 000000000..d8cd565b5 --- /dev/null +++ b/tests/topotests/isis-lfa-topo1/rt6/step1/show_yang_interface_isis_adjacencies.ref @@ -0,0 +1,44 @@ +{ + "frr-interface:lib": { + "interface": [ + { + "name": "eth-rt1", + "vrf": "default", + "state": { + "frr-isisd:isis": { + "adjacencies": { + "adjacency": [ + { + "neighbor-sys-type": "level-1", + "neighbor-sysid": "0000.0000.0001", + "hold-timer": 9, + "neighbor-priority": 0, + "state": "up" + } + ] + } + } + } + }, + { + "name": "eth-rt7", + "vrf": "default", + "state": { + "frr-isisd:isis": { + "adjacencies": { + "adjacency": [ + { + "neighbor-sys-type": "level-1", + "neighbor-sysid": "0000.0000.0007", + "hold-timer": 9, + "neighbor-priority": 0, + "state": "up" + } + ] + } + } + } + } + ] + } +} diff --git a/tests/topotests/isis-lfa-topo1/rt6/zebra.conf b/tests/topotests/isis-lfa-topo1/rt6/zebra.conf new file mode 100644 index 000000000..410807889 --- /dev/null +++ b/tests/topotests/isis-lfa-topo1/rt6/zebra.conf @@ -0,0 +1,16 @@ +log file zebra.log +! +hostname rt6 +! +debug zebra kernel +debug zebra packet +debug zebra mpls +! +interface lo + ip address 6.6.6.6/32 + ipv6 address 2001:db8:1000::6/128 +! +ip forwarding +! +line vty +! diff --git a/tests/topotests/isis-lfa-topo1/rt7/isisd.conf b/tests/topotests/isis-lfa-topo1/rt7/isisd.conf new file mode 100644 index 000000000..713e6d39f --- /dev/null +++ b/tests/topotests/isis-lfa-topo1/rt7/isisd.conf @@ -0,0 +1,51 @@ +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 + ipv6 router isis 1 + isis passive +! +interface eth-rt2 + ipv6 router isis 1 + isis metric 5 + isis network point-to-point + isis hello-multiplier 3 + isis fast-reroute lfa +! +interface eth-rt3 + ipv6 router isis 1 + isis network point-to-point + isis hello-multiplier 3 + isis fast-reroute lfa +! +interface eth-rt4 + ipv6 router isis 1 + isis metric 15 + isis network point-to-point + isis hello-multiplier 3 + isis fast-reroute lfa +! +interface eth-rt5 + ipv6 router isis 1 + isis network point-to-point + isis hello-multiplier 3 + isis fast-reroute lfa +! +interface eth-rt6 + ipv6 router isis 1 + isis network point-to-point + isis hello-multiplier 3 + isis fast-reroute lfa +! +router isis 1 + net 49.0000.0000.0000.0007.00 + is-type level-1 + lsp-gen-interval 2 + topology ipv6-unicast +! diff --git a/tests/topotests/isis-lfa-topo1/rt7/step1/show_ipv6_route.ref b/tests/topotests/isis-lfa-topo1/rt7/step1/show_ipv6_route.ref new file mode 100644 index 000000000..0dff15e3f --- /dev/null +++ b/tests/topotests/isis-lfa-topo1/rt7/step1/show_ipv6_route.ref @@ -0,0 +1,186 @@ +{ + "2001:db8:1000::1\/128":[ + { + "prefix":"2001:db8:1000::1\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":25, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt2", + "active":true, + "backupIndex":[ + 0, + 1, + 2, + 3 + ] + } + ], + "backupNexthops":[ + { + "afi":"ipv6", + "interfaceName":"eth-rt3", + "active":true + }, + { + "afi":"ipv6", + "interfaceName":"eth-rt4", + "active":true + }, + { + "afi":"ipv6", + "interfaceName":"eth-rt5", + "active":true + }, + { + "afi":"ipv6", + "interfaceName":"eth-rt6", + "active":true + } + ] + } + ], + "2001:db8:1000::2\/128":[ + { + "prefix":"2001:db8:1000::2\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":15, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt2", + "active":true, + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "afi":"ipv6", + "interfaceName":"eth-rt3", + "active":true + } + ] + } + ], + "2001:db8:1000::3\/128":[ + { + "prefix":"2001:db8:1000::3\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt3", + "active":true + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt2", + "active":true + } + ] + } + ], + "2001:db8:1000::4\/128":[ + { + "prefix":"2001:db8:1000::4\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":25, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt4", + "active":true, + "backupIndex":[ + 0, + 1 + ] + } + ], + "backupNexthops":[ + { + "afi":"ipv6", + "interfaceName":"eth-rt3", + "active":true + }, + { + "afi":"ipv6", + "interfaceName":"eth-rt6", + "active":true + } + ] + } + ], + "2001:db8:1000::5\/128":[ + { + "prefix":"2001:db8:1000::5\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt5", + "active":true + } + ] + } + ], + "2001:db8:1000::6\/128":[ + { + "prefix":"2001:db8:1000::6\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt6", + "active":true, + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "afi":"ipv6", + "interfaceName":"eth-rt4", + "active":true + } + ] + } + ] +} diff --git a/tests/topotests/isis-lfa-topo1/rt7/step1/show_yang_interface_isis_adjacencies.ref b/tests/topotests/isis-lfa-topo1/rt7/step1/show_yang_interface_isis_adjacencies.ref new file mode 100644 index 000000000..d8a7c5a9c --- /dev/null +++ b/tests/topotests/isis-lfa-topo1/rt7/step1/show_yang_interface_isis_adjacencies.ref @@ -0,0 +1,101 @@ +{ + "frr-interface:lib": { + "interface": [ + { + "name": "eth-rt2", + "vrf": "default", + "state": { + "frr-isisd:isis": { + "adjacencies": { + "adjacency": [ + { + "neighbor-sys-type": "level-1", + "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", + "neighbor-sysid": "0000.0000.0003", + "hold-timer": 9, + "neighbor-priority": 0, + "state": "up" + } + ] + } + } + } + }, + { + "name": "eth-rt4", + "vrf": "default", + "state": { + "frr-isisd:isis": { + "adjacencies": { + "adjacency": [ + { + "neighbor-sys-type": "level-1", + "neighbor-sysid": "0000.0000.0004", + "hold-timer": 9, + "neighbor-priority": 0, + "state": "up" + } + ] + } + } + } + }, + { + "name": "eth-rt5", + "vrf": "default", + "state": { + "frr-isisd:isis": { + "adjacencies": { + "adjacency": [ + { + "neighbor-sys-type": "level-1", + "neighbor-sysid": "0000.0000.0005", + "hold-timer": 9, + "neighbor-priority": 0, + "state": "up" + } + ] + } + } + } + }, + { + "name": "eth-rt6", + "vrf": "default", + "state": { + "frr-isisd:isis": { + "adjacencies": { + "adjacency": [ + { + "neighbor-sys-type": "level-1", + "neighbor-sysid": "0000.0000.0006", + "hold-timer": 9, + "neighbor-priority": 0, + "state": "up" + } + ] + } + } + } + } + ] + } +} diff --git a/tests/topotests/isis-lfa-topo1/rt7/zebra.conf b/tests/topotests/isis-lfa-topo1/rt7/zebra.conf new file mode 100644 index 000000000..353c9efa9 --- /dev/null +++ b/tests/topotests/isis-lfa-topo1/rt7/zebra.conf @@ -0,0 +1,16 @@ +log file zebra.log +! +hostname rt7 +! +debug zebra kernel +debug zebra packet +debug zebra mpls +! +interface lo + ip address 7.7.7.7/32 + ipv6 address 2001:db8:1000::7/128 +! +ip forwarding +! +line vty +! diff --git a/tests/topotests/isis-lfa-topo1/test_isis_lfa_topo1.py b/tests/topotests/isis-lfa-topo1/test_isis_lfa_topo1.py new file mode 100755 index 000000000..67edcae90 --- /dev/null +++ b/tests/topotests/isis-lfa-topo1/test_isis_lfa_topo1.py @@ -0,0 +1,545 @@ +#!/usr/bin/env python + +# +# test_isis_tilfa_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_lfa_topo1.py: + + +---------+ + | | + +--------------------------------+ RT1 +-------------------------------+ + | +-------------+ +-------------+ | + | | | | | | + | | +----+----+ | | + | | | |20 | + | | | | | + | | | | | + +----+----+ +----+----+ +----+----+ +----+----+ +----+----+ + | | | | | | | | | | + | RT2 | 5 | RT3 | | RT4 | | RT5 | | RT6 | + | +--------+ | | | | | | | + | | | | | | | | | | + +----+----+ +----+----+ +----+----+ +----+----+ +----+----+ + | | | | | + | | |15 | | + |5 | | | | + | | +----+----+ | | + | | | | | | + | +-------------+ RT7 +-------------+ | + +--------------------------------+ +-------------------------------+ + | | + +---------+ +""" + +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']: + 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['rt2'], nodeif="eth-rt3") + switch.add_link(tgen.gears['rt3'], nodeif="eth-rt2") + switch = tgen.add_switch('s3') + switch.add_link(tgen.gears['rt1'], nodeif="eth-rt3") + switch.add_link(tgen.gears['rt3'], nodeif="eth-rt1") + switch = tgen.add_switch('s4') + switch.add_link(tgen.gears['rt1'], nodeif="eth-rt4") + switch.add_link(tgen.gears['rt4'], nodeif="eth-rt1") + switch = tgen.add_switch('s5') + switch.add_link(tgen.gears['rt1'], nodeif="eth-rt5") + switch.add_link(tgen.gears['rt5'], nodeif="eth-rt1") + switch = tgen.add_switch('s6') + switch.add_link(tgen.gears['rt1'], nodeif="eth-rt6") + switch.add_link(tgen.gears['rt6'], nodeif="eth-rt1") + switch = tgen.add_switch('s7') + switch.add_link(tgen.gears['rt2'], nodeif="eth-rt7") + switch.add_link(tgen.gears['rt7'], nodeif="eth-rt2") + switch = tgen.add_switch('s8') + switch.add_link(tgen.gears['rt3'], nodeif="eth-rt7") + switch.add_link(tgen.gears['rt7'], nodeif="eth-rt3") + switch = tgen.add_switch('s9') + switch.add_link(tgen.gears['rt4'], nodeif="eth-rt7") + switch.add_link(tgen.gears['rt7'], nodeif="eth-rt4") + switch = tgen.add_switch('s10') + switch.add_link(tgen.gears['rt5'], nodeif="eth-rt7") + switch.add_link(tgen.gears['rt7'], nodeif="eth-rt5") + switch = tgen.add_switch('s11') + switch.add_link(tgen.gears['rt6'], nodeif="eth-rt7") + switch.add_link(tgen.gears['rt7'], nodeif="eth-rt6") + + # + # Populate multi-dimensional dictionary containing all expected outputs + # + files = ["show_ipv6_route.ref", + "show_yang_interface_isis_adjacencies.ref"] + for rname in ['rt1', 'rt2', 'rt3', 'rt4', 'rt5', 'rt6', 'rt7']: + outputs[rname] = {} + for step in range(1, 13 + 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 rname != "rt1": + continue + 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)) + ) + + 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', 'rt2', 'rt3', 'rt4', 'rt5', 'rt6', 'rt7']: + 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_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', 'rt2', 'rt3', 'rt4', 'rt5', 'rt6', 'rt7']: + router_compare_json_output(rname, "show ipv6 route isis json", + outputs[rname][1]["show_ipv6_route.ref"]) + +# +# Step 2 +# +# Action(s): +# -Disable LFA protection on all interfaces +# +# Expected changes: +# -rt1 should uninstall all backup nexthops from all routes +# +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) + + logger.info('Disabling LFA protection on all rt1 interfaces') + tgen.net['rt1'].cmd('vtysh -c "conf t" -c "interface eth-rt2" -c "no isis fast-reroute lfa"') + tgen.net['rt1'].cmd('vtysh -c "conf t" -c "interface eth-rt3" -c "no isis fast-reroute lfa"') + tgen.net['rt1'].cmd('vtysh -c "conf t" -c "interface eth-rt4" -c "no isis fast-reroute lfa"') + tgen.net['rt1'].cmd('vtysh -c "conf t" -c "interface eth-rt5" -c "no isis fast-reroute lfa"') + tgen.net['rt1'].cmd('vtysh -c "conf t" -c "interface eth-rt6" -c "no isis fast-reroute lfa"') + + 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): +# -Re-enable LFA protection on all interfaces +# +# Expected changes: +# -Revert changes from the previous step +# +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) + + logger.info('Re-enabling LFA protection on all rt1 interfaces') + tgen.net['rt1'].cmd('vtysh -c "conf t" -c "interface eth-rt2" -c "isis fast-reroute lfa"') + tgen.net['rt1'].cmd('vtysh -c "conf t" -c "interface eth-rt3" -c "isis fast-reroute lfa"') + tgen.net['rt1'].cmd('vtysh -c "conf t" -c "interface eth-rt4" -c "isis fast-reroute lfa"') + tgen.net['rt1'].cmd('vtysh -c "conf t" -c "interface eth-rt5" -c "isis fast-reroute lfa"') + tgen.net['rt1'].cmd('vtysh -c "conf t" -c "interface eth-rt6" -c "isis fast-reroute lfa"') + + 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 LFA load-sharing +# +# Expected changes: +# -rt1 should use at most one backup nexthop for each route +# +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) + + logger.info('Disabling LFA load-sharing on rt1') + tgen.net['rt1'].cmd('vtysh -c "conf t" -c "router isis 1" -c "fast-reroute load-sharing disable"') + + 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): +# -Re-enable LFA load-sharing +# +# Expected changes: +# -Revert changes from the previous step +# +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) + + logger.info('Re-enabling LFA load-sharing on rt1') + tgen.net['rt1'].cmd('vtysh -c "conf t" -c "router isis 1" -c "no fast-reroute load-sharing disable"') + + 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): +# -Limit backup computation to critical priority prefixes only +# +# Expected changes: +# -rt1 should uninstall all backup nexthops from all routes +# +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) + + logger.info('Limiting backup computation to critical priority prefixes only') + tgen.net['rt1'].cmd('vtysh -c "conf t" -c "router isis 1" -c "fast-reroute priority-limit critical"') + + 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 prefix priority list to classify rt7's loopback as a +# critical-priority prefix +# +# Expected changes: +# -rt1 should install backup nexthops for rt7's loopback route. +# +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) + + logger.info('Configuring a prefix priority list') + tgen.net['rt1'].cmd('vtysh -c "conf t" -c "router isis 1" -c "spf prefix-priority critical CRITICAL_DESTINATIONS"') + tgen.net['rt1'].cmd('vtysh -c "conf t" -c "ipv6 access-list CRITICAL_DESTINATIONS seq 5 permit 2001:db8:1000::7/128"') + + 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): +# -Revert previous changes related to prefix priorities +# +# Expected changes: +# -Revert changes from the previous two steps +# +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) + + logger.info('Reverting previous changes related to prefix priorities') + tgen.net['rt1'].cmd('vtysh -c "conf t" -c "no ipv6 access-list CRITICAL_DESTINATIONS seq 5 permit 2001:db8:1000::7/128"') + tgen.net['rt1'].cmd('vtysh -c "conf t" -c "router isis 1" -c "no fast-reroute priority-limit critical"') + tgen.net['rt1'].cmd('vtysh -c "conf t" -c "router isis 1" -c "no spf prefix-priority critical CRITICAL_DESTINATIONS"') + + 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): +# -Exclude eth-rt6 from LFA computation for eth-rt2's failure +# +# Expected changes: +# -Uninstall the eth-rt2 protecting backup nexthops that go through eth-rt6 +# +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) + + logger.info('Excluding eth-rt6 from LFA computation for eth-rt2\'s failure') + tgen.net['rt1'].cmd('vtysh -c "conf t" -c "interface eth-rt2" -c "isis fast-reroute lfa exclude interface eth-rt6"') + + 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): +# -Remove exclusion of eth-rt6 from LFA computation for eth-rt2's failure +# +# Expected changes: +# -Revert changes from the previous step +# +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) + + logger.info('Removing exclusion of eth-rt6 from LFA computation for eth-rt2\'s failure') + tgen.net['rt1'].cmd('vtysh -c "conf t" -c "interface eth-rt2" -c "no isis fast-reroute lfa exclude interface eth-rt6"') + + for rname in ['rt1']: + router_compare_json_output(rname, "show ipv6 route isis json", + outputs[rname][10]["show_ipv6_route.ref"]) + +# +# Step 11 +# +# Action(s): +# -Add LFA tiebreaker: prefer node protecting backup path +# +# Expected changes: +# -rt1 should prefer backup nexthops that provide node protection +# +def test_rib_ipv6_step11(): + logger.info("Test (step 11): verify IPv6 RIB") + tgen = get_topogen() + + # Skip if previous fatal error condition is raised + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + logger.info('Adding LFA tiebreaker: prefer node protecting backup path') + tgen.net['rt1'].cmd('vtysh -c "conf t" -c "router isis 1" -c "fast-reroute lfa tiebreaker node-protecting index 10"') + + for rname in ['rt1']: + router_compare_json_output(rname, "show ipv6 route isis json", + outputs[rname][11]["show_ipv6_route.ref"]) + +# +# Step 12 +# +# Action(s): +# -Add LFA tiebreaker: prefer backup path via downstream node +# +# Expected changes: +# -rt1 should prefer backup nexthops that satisfy the downstream condition +# +def test_rib_ipv6_step12(): + logger.info("Test (step 12): verify IPv6 RIB") + tgen = get_topogen() + + # Skip if previous fatal error condition is raised + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + logger.info('Adding LFA tiebreaker: prefer backup path via downstream node') + tgen.net['rt1'].cmd('vtysh -c "conf t" -c "router isis 1" -c "fast-reroute lfa tiebreaker downstream index 20"') + + for rname in ['rt1']: + router_compare_json_output(rname, "show ipv6 route isis json", + outputs[rname][12]["show_ipv6_route.ref"]) + +# +# Step 13 +# +# Action(s): +# -Add LFA tiebreaker: prefer backup path with lowest total metric +# +# Expected changes: +# -rt1 should prefer backup nexthops that have the best metric +# +def test_rib_ipv6_step13(): + logger.info("Test (step 13): verify IPv6 RIB") + tgen = get_topogen() + + # Skip if previous fatal error condition is raised + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + logger.info('Adding LFA tiebreaker: prefer backup path with lowest total metric') + tgen.net['rt1'].cmd('vtysh -c "conf t" -c "router isis 1" -c "fast-reroute lfa tiebreaker lowest-backup-metric index 30"') + + for rname in ['rt1']: + router_compare_json_output(rname, "show ipv6 route isis json", + outputs[rname][13]["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)) diff --git a/yang/frr-isisd.yang b/yang/frr-isisd.yang index c3b39e375..d751a19f0 100644 --- a/yang/frr-isisd.yang +++ b/yang/frr-isisd.yang @@ -244,6 +244,10 @@ module frr-isisd { } } + typedef access-list-ref { + type string; + } + grouping redistribute-attributes { description "Common optional attributes of any redistribute entry."; @@ -336,6 +340,94 @@ module frr-isisd { } } + grouping global-config-lfa { + container lfa { + description + "LFA configuration."; + + leaf load-sharing { + type boolean; + default "true"; + description + "Load share prefixes across multiple backups."; + } + leaf priority-limit { + type enumeration { + enum "critical" { + value 0; + description + "Compute for critical priority prefixes only."; + } + enum "high" { + value 1; + description + "Compute for critical & high priority prefixes."; + } + enum "medium" { + value 2; + description + "Compute for critical, high & medium priority prefixes."; + } + } + description + "Limit backup computation up to the prefix priority."; + } + list tiebreaker { + key "index"; + unique "type"; + description + "Configure tiebreaker for multiple backups."; + leaf index { + type uint8 { + range "1..255"; + } + description + "Preference order among tiebreakers."; + } + leaf type { + type enumeration { + enum "downstream" { + value 0; + description + "Prefer backup path via downstream node."; + } + enum "lowest-backup-metric" { + value 1; + description + "Prefer backup path with lowest total metric."; + } + enum "node-protecting" { + value 2; + description + "Prefer node protecting backup path."; + } + } + mandatory true; + description + "Tiebreaker type."; + } + } + } + } + + grouping interface-config-lfa { + container lfa { + description + "LFA configuration."; + leaf enable { + type boolean; + default false; + description + "Enables LFA computation."; + } + leaf-list exclude-interface { + type frr-interface:interface-ref; + description + "Exclude an interface from computation."; + } + } + } + grouping interface-config-ti-lfa { container ti-lfa { description @@ -664,11 +756,21 @@ module frr-isisd { container level-1 { description "Level-1 IP Fast-reroute configuration."; + must "./lfa/enable = 'false' or ./ti-lfa/enable = 'false'" { + error-message + "Can't enable both classic LFA and TI-LFA in the same interface."; + } + uses interface-config-lfa; uses interface-config-ti-lfa; } container level-2 { description "Level-2 IP Fast-reroute configuration."; + must "./lfa/enable = 'false' or ./ti-lfa/enable = 'false'" { + error-message + "Can't enable both classic LFA and TI-LFA in the same interface."; + } + uses interface-config-lfa; uses interface-config-ti-lfa; } } @@ -1095,6 +1197,42 @@ module frr-isisd { "Minimum time between consecutive level-2 SPFs."; } } + + container prefix-priorities { + description + "SPF Prefix Priority configuration"; + + container critical { + description + "Critical prefix priority"; + leaf access-list-name { + type access-list-ref; + description + "Access List to determine prefixes for + this priority"; + } + } + container high { + description + "High prefix priority"; + leaf access-list-name { + type access-list-ref; + description + "Access List to determine prefixes for + this priority"; + } + } + container medium { + description + "Medium prefix priority"; + leaf access-list-name { + type access-list-ref; + description + "Access List to determine prefixes for + this priority"; + } + } + } } container area-password { @@ -1249,6 +1387,21 @@ module frr-isisd { } } + container fast-reroute { + description + "IP Fast-reroute configuration."; + container level-1 { + description + "Level-1 IP Fast-reroute configuration."; + uses global-config-lfa; + } + container level-2 { + description + "Level-2 IP Fast-reroute configuration."; + uses global-config-lfa; + } + } + leaf log-adjacency-changes { type boolean; default "false"; |