diff --git a/doc/user/isisd.rst b/doc/user/isisd.rst index 595bae143e..66f8fd5678 100644 --- a/doc/user/isisd.rst +++ b/doc/user/isisd.rst @@ -261,10 +261,11 @@ ISIS interface Limit Remote LFA PQ node selection within the specified metric. -.. clicmd:: isis fast-reroute ti-lfa [level-1|level-2] [node-protection] +.. clicmd:: isis fast-reroute ti-lfa [level-1|level-2] [node-protection [link-fallback]] Enable per-prefix TI-LFA fast reroute link or node protection. - + When node protection is used, option link-fallback enables the computation and use of + link-protecting LFAs for destinations unprotected by node protection. .. _showing-isis-information: diff --git a/isisd/isis_circuit.h b/isisd/isis_circuit.h index 45c0a7e0ed..84c3ca3ff2 100644 --- a/isisd/isis_circuit.h +++ b/isisd/isis_circuit.h @@ -152,6 +152,7 @@ struct isis_circuit { struct hash *lfa_excluded_ifaces[ISIS_LEVELS]; bool tilfa_protection[ISIS_LEVELS]; bool tilfa_node_protection[ISIS_LEVELS]; + bool tilfa_link_fallback[ISIS_LEVELS]; /* * Counters as in 10589--11.2.5.9 */ diff --git a/isisd/isis_cli.c b/isisd/isis_cli.c index 3e719df4bb..f316e0279c 100644 --- a/isisd/isis_cli.c +++ b/isisd/isis_cli.c @@ -2647,6 +2647,7 @@ void cli_show_ip_isis_frr(struct vty *vty, struct lyd_node *dnode, { bool l1_enabled, l2_enabled; bool l1_node_protection, l2_node_protection; + bool l1_link_fallback, l2_link_fallback; /* Classic LFA */ l1_enabled = yang_dnode_get_bool(dnode, "./level-1/lfa/enable"); @@ -2692,13 +2693,21 @@ void cli_show_ip_isis_frr(struct vty *vty, struct lyd_node *dnode, 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"); + l1_link_fallback = + yang_dnode_get_bool(dnode, "./level-1/ti-lfa/link-fallback"); + l2_link_fallback = + yang_dnode_get_bool(dnode, "./level-2/ti-lfa/link-fallback"); + if (l1_enabled || l2_enabled) { if (l1_enabled == l2_enabled - && l1_node_protection == l2_node_protection) { + && l1_node_protection == l2_node_protection + && l1_link_fallback == l2_link_fallback) { vty_out(vty, " isis fast-reroute ti-lfa"); if (l1_node_protection) vty_out(vty, " node-protection"); + if (l1_link_fallback) + vty_out(vty, " link-fallback"); vty_out(vty, "\n"); } else { if (l1_enabled) { @@ -2706,6 +2715,8 @@ void cli_show_ip_isis_frr(struct vty *vty, struct lyd_node *dnode, " isis fast-reroute ti-lfa level-1"); if (l1_node_protection) vty_out(vty, " node-protection"); + if (l1_link_fallback) + vty_out(vty, " link-fallback"); vty_out(vty, "\n"); } if (l2_enabled) { @@ -2713,6 +2724,8 @@ void cli_show_ip_isis_frr(struct vty *vty, struct lyd_node *dnode, " isis fast-reroute ti-lfa level-2"); if (l2_node_protection) vty_out(vty, " node-protection"); + if (l2_link_fallback) + vty_out(vty, " link-fallback"); vty_out(vty, "\n"); } } @@ -2917,14 +2930,15 @@ void cli_show_frr_remote_lfa_max_metric(struct vty *vty, struct lyd_node *dnode, * 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]", + "[no] isis fast-reroute ti-lfa [level-1|level-2]$level [node-protection$node_protection [link-fallback$link_fallback]]", NO_STR "IS-IS routing protocol\n" "Interface IP Fast-reroute configuration\n" "Enable TI-LFA computation\n" "Enable TI-LFA computation for Level 1 only\n" "Enable TI-LFA computation for Level 2 only\n" - "Protect against node failures\n") + "Protect against node failures\n" + "Enable link-protection fallback\n") { if (!level || strmatch(level, "level-1")) { if (no) { @@ -2936,6 +2950,10 @@ DEFPY(isis_ti_lfa, isis_ti_lfa_cmd, vty, "./frr-isisd:isis/fast-reroute/level-1/ti-lfa/node-protection", NB_OP_MODIFY, "false"); + nb_cli_enqueue_change( + vty, + "./frr-isisd:isis/fast-reroute/level-1/ti-lfa/link-fallback", + NB_OP_MODIFY, "false"); } else { nb_cli_enqueue_change( vty, @@ -2946,6 +2964,10 @@ DEFPY(isis_ti_lfa, isis_ti_lfa_cmd, "./frr-isisd:isis/fast-reroute/level-1/ti-lfa/node-protection", NB_OP_MODIFY, node_protection ? "true" : "false"); + nb_cli_enqueue_change( + vty, + "./frr-isisd:isis/fast-reroute/level-1/ti-lfa/link-fallback", + NB_OP_MODIFY, link_fallback ? "true" : "false"); } } if (!level || strmatch(level, "level-2")) { @@ -2958,6 +2980,10 @@ DEFPY(isis_ti_lfa, isis_ti_lfa_cmd, vty, "./frr-isisd:isis/fast-reroute/level-2/ti-lfa/node-protection", NB_OP_MODIFY, "false"); + nb_cli_enqueue_change( + vty, + "./frr-isisd:isis/fast-reroute/level-2/ti-lfa/link-fallback", + NB_OP_MODIFY, "false"); } else { nb_cli_enqueue_change( vty, @@ -2968,6 +2994,10 @@ DEFPY(isis_ti_lfa, isis_ti_lfa_cmd, "./frr-isisd:isis/fast-reroute/level-2/ti-lfa/node-protection", NB_OP_MODIFY, node_protection ? "true" : "false"); + nb_cli_enqueue_change( + vty, + "./frr-isisd:isis/fast-reroute/level-2/ti-lfa/link-fallback", + NB_OP_MODIFY, link_fallback ? "true" : "false"); } } diff --git a/isisd/isis_lfa.c b/isisd/isis_lfa.c index b535924e93..e033c28fef 100644 --- a/isisd/isis_lfa.c +++ b/isisd/isis_lfa.c @@ -2258,6 +2258,11 @@ static void isis_spf_run_tilfa(struct isis_area *area, spftree_pc_node = isis_tilfa_compute(area, spftree, spftree_reverse, resource); isis_spftree_del(spftree_pc_node); + + /* don't do link protection unless link-fallback is configured + */ + if (!circuit->tilfa_link_fallback[spftree->level - 1]) + return; } /* Compute link protecting repair paths. */ diff --git a/isisd/isis_nb.c b/isisd/isis_nb.c index 4eac8de2cb..ecad16229c 100644 --- a/isisd/isis_nb.c +++ b/isisd/isis_nb.c @@ -977,6 +977,12 @@ const struct frr_yang_module_info frr_isisd_info = { .modify = lib_interface_isis_fast_reroute_level_1_ti_lfa_node_protection_modify, } }, + { + .xpath = "/frr-interface:lib/interface/frr-isisd:isis/fast-reroute/level-1/ti-lfa/link-fallback", + .cbs = { + .modify = lib_interface_isis_fast_reroute_level_1_ti_lfa_link_fallback_modify, + } + }, { .xpath = "/frr-interface:lib/interface/frr-isisd:isis/fast-reroute/level-2/lfa/enable", .cbs = { @@ -1017,6 +1023,12 @@ const struct frr_yang_module_info frr_isisd_info = { .modify = lib_interface_isis_fast_reroute_level_2_ti_lfa_node_protection_modify, } }, + { + .xpath = "/frr-interface:lib/interface/frr-isisd:isis/fast-reroute/level-2/ti-lfa/link-fallback", + .cbs = { + .modify = lib_interface_isis_fast_reroute_level_2_ti_lfa_link_fallback_modify, + } + }, { .xpath = "/frr-interface:lib/interface/state/frr-isisd:isis", .cbs = { diff --git a/isisd/isis_nb.h b/isisd/isis_nb.h index 94aa00c975..0c2f7b6b7e 100644 --- a/isisd/isis_nb.h +++ b/isisd/isis_nb.h @@ -319,6 +319,8 @@ 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_1_ti_lfa_link_fallback_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( @@ -335,6 +337,8 @@ 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( struct nb_cb_modify_args *args); +int lib_interface_isis_fast_reroute_level_2_ti_lfa_link_fallback_modify( + struct nb_cb_modify_args *args); struct yang_data * lib_interface_state_isis_get_elem(struct nb_cb_get_elem_args *args); const void *lib_interface_state_isis_adjacencies_adjacency_get_next( diff --git a/isisd/isis_nb_config.c b/isisd/isis_nb_config.c index f9028bdd9f..5ca2329dd3 100644 --- a/isisd/isis_nb_config.c +++ b/isisd/isis_nb_config.c @@ -3516,6 +3516,30 @@ int lib_interface_isis_fast_reroute_level_1_ti_lfa_node_protection_modify( return NB_OK; } +/* + * XPath: + * /frr-interface:lib/interface/frr-isisd:isis/fast-reroute/level-1/ti-lfa/link-fallback + */ +int lib_interface_isis_fast_reroute_level_1_ti_lfa_link_fallback_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->tilfa_link_fallback[0] = + yang_dnode_get_bool(args->dnode, NULL); + + area = circuit->area; + if (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/enable @@ -3720,3 +3744,27 @@ int lib_interface_isis_fast_reroute_level_2_ti_lfa_node_protection_modify( return NB_OK; } + +/* + * XPath: + * /frr-interface:lib/interface/frr-isisd:isis/fast-reroute/level-2/ti-lfa/link-fallback + */ +int lib_interface_isis_fast_reroute_level_2_ti_lfa_link_fallback_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->tilfa_link_fallback[1] = + yang_dnode_get_bool(args->dnode, NULL); + + area = circuit->area; + if (area) + lsp_regenerate_schedule(area, area->is_type, 0); + + return NB_OK; +} diff --git a/yang/frr-isisd.yang b/yang/frr-isisd.yang index 46ad8d3971..4653e6f009 100644 --- a/yang/frr-isisd.yang +++ b/yang/frr-isisd.yang @@ -493,6 +493,13 @@ module frr-isisd { description "Node protection is provided by the alternate."; } + leaf link-fallback { + type boolean; + must ". = 'false' or ../enable = 'true'"; + default false; + description + "Fallback to link protection."; + } } }