mirror of
https://git.proxmox.com/git/mirror_frr
synced 2025-08-02 18:52:04 +00:00
isisd: apply fast-reroute on an adjacency failure
When a adjacency falls down, the primary routes are not deleted on the dataplane until the SPF is recomputed. Even the backup routes are pre-installed on the dataplane, there is no fast-route optimization. Reasons for an adjacency to come down are: - BFD down - Hello timer timeout - User adjacency clear Apply the backup route switchover for fast-reroute as soon an IS-IS adjacency falls down before the first SPF re-computation. Pre-computed backup routes are applied sooner. Signed-off-by: Louis Scalbert <louis.scalbert@6wind.com>
This commit is contained in:
parent
6eb8da37b0
commit
694fa86728
@ -212,6 +212,36 @@ static const char *adj_level2string(int level)
|
||||
return NULL; /* not reached */
|
||||
}
|
||||
|
||||
static void isis_adj_route_switchover(struct isis_adjacency *adj)
|
||||
{
|
||||
union g_addr ip = {};
|
||||
ifindex_t ifindex;
|
||||
unsigned int i;
|
||||
|
||||
if (!adj->circuit || !adj->circuit->interface)
|
||||
return;
|
||||
|
||||
ifindex = adj->circuit->interface->ifindex;
|
||||
|
||||
for (i = 0; i < adj->ipv4_address_count; i++) {
|
||||
ip.ipv4 = adj->ipv4_addresses[i];
|
||||
isis_circuit_switchover_routes(adj->circuit, AF_INET, &ip,
|
||||
ifindex);
|
||||
}
|
||||
|
||||
for (i = 0; i < adj->ll_ipv6_count; i++) {
|
||||
ip.ipv6 = adj->ll_ipv6_addrs[i];
|
||||
isis_circuit_switchover_routes(adj->circuit, AF_INET6, &ip,
|
||||
ifindex);
|
||||
}
|
||||
|
||||
for (i = 0; i < adj->global_ipv6_count; i++) {
|
||||
ip.ipv6 = adj->global_ipv6_addrs[i];
|
||||
isis_circuit_switchover_routes(adj->circuit, AF_INET6, &ip,
|
||||
ifindex);
|
||||
}
|
||||
}
|
||||
|
||||
void isis_adj_process_threeway(struct isis_adjacency *adj,
|
||||
struct isis_threeway_adj *tw_adj,
|
||||
enum isis_adj_usage adj_usage)
|
||||
@ -298,6 +328,15 @@ void isis_adj_state_change(struct isis_adjacency **padj,
|
||||
if (new_state == old_state)
|
||||
return;
|
||||
|
||||
if (old_state == ISIS_ADJ_UP) {
|
||||
if (IS_DEBUG_EVENTS)
|
||||
zlog_debug(
|
||||
"ISIS-Adj (%s): Starting fast-reroute on state change %d->%d: %s",
|
||||
circuit->area->area_tag, old_state, new_state,
|
||||
reason ? reason : "unspecified");
|
||||
isis_adj_route_switchover(adj);
|
||||
}
|
||||
|
||||
adj->adj_state = new_state;
|
||||
send_hello_sched(circuit, adj->level, TRIGGERED_IIH_DELAY);
|
||||
|
||||
|
@ -151,5 +151,4 @@ void isis_adj_build_up_list(struct list *adjdb, struct list *list);
|
||||
int isis_adj_usage2levels(enum isis_adj_usage usage);
|
||||
void isis_bfd_startup_timer(struct thread *thread);
|
||||
const char *isis_adj_name(const struct isis_adjacency *adj);
|
||||
|
||||
#endif /* ISIS_ADJACENCY_H */
|
||||
|
@ -598,6 +598,32 @@ size_t isis_circuit_pdu_size(struct isis_circuit *circuit)
|
||||
return ISO_MTU(circuit);
|
||||
}
|
||||
|
||||
static bool isis_circuit_lfa_enabled(struct isis_circuit *circuit, int level)
|
||||
{
|
||||
return (circuit->lfa_protection[level - 1] ||
|
||||
circuit->rlfa_protection[level - 1] ||
|
||||
circuit->tilfa_protection[level - 1]);
|
||||
}
|
||||
|
||||
void isis_circuit_switchover_routes(struct isis_circuit *circuit, int family,
|
||||
union g_addr *nexthop_ip, ifindex_t ifindex)
|
||||
{
|
||||
char is_type;
|
||||
|
||||
if (!circuit->area)
|
||||
return;
|
||||
|
||||
is_type = circuit->area->is_type;
|
||||
if ((is_type == IS_LEVEL_1 || is_type == IS_LEVEL_1_AND_2) &&
|
||||
isis_circuit_lfa_enabled(circuit, IS_LEVEL_1))
|
||||
isis_area_switchover_routes(circuit->area, family, nexthop_ip,
|
||||
ifindex, IS_LEVEL_1);
|
||||
if ((is_type == IS_LEVEL_2 || is_type == IS_LEVEL_1_AND_2) &&
|
||||
isis_circuit_lfa_enabled(circuit, IS_LEVEL_2))
|
||||
isis_area_switchover_routes(circuit->area, family, nexthop_ip,
|
||||
ifindex, IS_LEVEL_2);
|
||||
}
|
||||
|
||||
void isis_circuit_stream(struct isis_circuit *circuit, struct stream **stream)
|
||||
{
|
||||
size_t stream_size = isis_circuit_pdu_size(circuit);
|
||||
|
@ -28,6 +28,7 @@
|
||||
#include "qobj.h"
|
||||
#include "prefix.h"
|
||||
#include "ferr.h"
|
||||
#include "nexthop.h"
|
||||
|
||||
#include "isis_constants.h"
|
||||
#include "isis_common.h"
|
||||
@ -209,6 +210,9 @@ void isis_circuit_print_vty(struct isis_circuit *circuit, struct vty *vty,
|
||||
void isis_circuit_print_json(struct isis_circuit *circuit,
|
||||
struct json_object *json, char detail);
|
||||
size_t isis_circuit_pdu_size(struct isis_circuit *circuit);
|
||||
void isis_circuit_switchover_routes(struct isis_circuit *circuit, int family,
|
||||
union g_addr *nexthop_ip,
|
||||
ifindex_t ifindex);
|
||||
void isis_circuit_stream(struct isis_circuit *circuit, struct stream **stream);
|
||||
|
||||
void isis_circuit_af_set(struct isis_circuit *circuit, bool ip_router,
|
||||
|
@ -724,3 +724,53 @@ void isis_route_invalidate_table(struct isis_area *area,
|
||||
UNSET_FLAG(rinfo->flag, ISIS_ROUTE_FLAG_ACTIVE);
|
||||
}
|
||||
}
|
||||
|
||||
void isis_route_switchover_nexthop(struct isis_area *area,
|
||||
struct route_table *table, int family,
|
||||
union g_addr *nexthop_addr,
|
||||
ifindex_t ifindex)
|
||||
{
|
||||
const char *ifname = NULL, *vrfname = NULL;
|
||||
struct isis_route_info *rinfo;
|
||||
struct prefix_ipv6 *src_p;
|
||||
struct route_node *rnode;
|
||||
vrf_id_t vrf_id;
|
||||
struct prefix *prefix;
|
||||
|
||||
if (IS_DEBUG_EVENTS) {
|
||||
if (area && area->isis) {
|
||||
vrf_id = area->isis->vrf_id;
|
||||
vrfname = vrf_id_to_name(vrf_id);
|
||||
ifname = ifindex2ifname(ifindex, vrf_id);
|
||||
}
|
||||
zlog_debug("%s: initiating fast-reroute %s on VRF %s iface %s",
|
||||
__func__, family2str(family), vrfname ? vrfname : "",
|
||||
ifname ? ifname : "");
|
||||
}
|
||||
|
||||
for (rnode = route_top(table); rnode;
|
||||
rnode = srcdest_route_next(rnode)) {
|
||||
if (!rnode->info)
|
||||
continue;
|
||||
rinfo = rnode->info;
|
||||
|
||||
if (!rinfo->backup)
|
||||
continue;
|
||||
|
||||
if (!nexthoplookup(rinfo->nexthops, family, nexthop_addr,
|
||||
ifindex))
|
||||
continue;
|
||||
|
||||
srcdest_rnode_prefixes(rnode, (const struct prefix **)&prefix,
|
||||
(const struct prefix **)&src_p);
|
||||
|
||||
/* Switchover route. */
|
||||
UNSET_FLAG(rinfo->flag, ISIS_ROUTE_FLAG_ZEBRA_SYNCED);
|
||||
isis_route_update(area, prefix, src_p, rinfo->backup);
|
||||
|
||||
isis_route_info_delete(rinfo);
|
||||
|
||||
rnode->info = NULL;
|
||||
route_unlock_node(rnode);
|
||||
}
|
||||
}
|
||||
|
@ -86,4 +86,9 @@ void isis_route_invalidate_table(struct isis_area *area,
|
||||
void isis_route_node_cleanup(struct route_table *table,
|
||||
struct route_node *node);
|
||||
|
||||
void isis_route_switchover_nexthop(struct isis_area *area,
|
||||
struct route_table *table, int family,
|
||||
union g_addr *nexthop_addr,
|
||||
ifindex_t ifindex);
|
||||
|
||||
#endif /* _ZEBRA_ISIS_ROUTE_H */
|
||||
|
@ -1851,6 +1851,15 @@ void isis_spf_invalidate_routes(struct isis_spftree *tree)
|
||||
tree->route_table_backup->cleanup = isis_route_node_cleanup;
|
||||
}
|
||||
|
||||
void isis_spf_switchover_routes(struct isis_area *area,
|
||||
struct isis_spftree **trees, int family,
|
||||
union g_addr *nexthop_ip, ifindex_t ifindex,
|
||||
int level)
|
||||
{
|
||||
isis_route_switchover_nexthop(area, trees[level - 1]->route_table,
|
||||
family, nexthop_ip, ifindex);
|
||||
}
|
||||
|
||||
static void isis_run_spf_cb(struct thread *thread)
|
||||
{
|
||||
struct isis_spf_run *run = THREAD_ARG(thread);
|
||||
|
@ -60,6 +60,10 @@ struct isis_vertex *isis_spf_prefix_sid_lookup(struct isis_spftree *spftree,
|
||||
void isis_spf_invalidate_routes(struct isis_spftree *tree);
|
||||
void isis_spf_verify_routes(struct isis_area *area,
|
||||
struct isis_spftree **trees);
|
||||
void isis_spf_switchover_routes(struct isis_area *area,
|
||||
struct isis_spftree **trees, int family,
|
||||
union g_addr *nexthop_ip, ifindex_t ifindex,
|
||||
int level);
|
||||
void isis_spftree_del(struct isis_spftree *spftree);
|
||||
void spftree_area_init(struct isis_area *area);
|
||||
void spftree_area_del(struct isis_area *area);
|
||||
|
@ -3092,6 +3092,25 @@ void isis_area_verify_routes(struct isis_area *area)
|
||||
isis_spf_verify_routes(area, area->spftree[tree]);
|
||||
}
|
||||
|
||||
void isis_area_switchover_routes(struct isis_area *area, int family,
|
||||
union g_addr *nexthop_ip, ifindex_t ifindex,
|
||||
int level)
|
||||
{
|
||||
int tree;
|
||||
|
||||
/* TODO SPFTREE_DSTSRC */
|
||||
if (family == AF_INET)
|
||||
tree = SPFTREE_IPV4;
|
||||
else if (family == AF_INET6)
|
||||
tree = SPFTREE_IPV6;
|
||||
else
|
||||
return;
|
||||
|
||||
isis_spf_switchover_routes(area, area->spftree[tree], family,
|
||||
nexthop_ip, ifindex, level);
|
||||
}
|
||||
|
||||
|
||||
static void area_resign_level(struct isis_area *area, int level)
|
||||
{
|
||||
isis_area_invalidate_routes(area, level);
|
||||
|
@ -291,6 +291,9 @@ struct isis_lsp *lsp_for_sysid(struct lspdb_head *head, const char *sysid_str,
|
||||
|
||||
void isis_area_invalidate_routes(struct isis_area *area, int levels);
|
||||
void isis_area_verify_routes(struct isis_area *area);
|
||||
void isis_area_switchover_routes(struct isis_area *area, int family,
|
||||
union g_addr *nexthop_ip, ifindex_t ifindex,
|
||||
int level);
|
||||
|
||||
void isis_area_overload_bit_set(struct isis_area *area, bool overload_bit);
|
||||
void isis_area_overload_on_startup_set(struct isis_area *area,
|
||||
|
Loading…
Reference in New Issue
Block a user