diff options
| author | Louis Scalbert <louis.scalbert@6wind.com> | 2022-03-21 17:59:27 +0100 | 
|---|---|---|
| committer | Louis Scalbert <louis.scalbert@6wind.com> | 2022-05-23 10:44:20 +0200 | 
| commit | 71252973234e70ffa3cb5eec43d4efc1be3d3331 (patch) | |
| tree | c7c00e31f29781ca3ec9f3697550b2c94671c618 /isisd | |
| parent | 44937c5450320eb119f9a4ea0c9bd32600d8e007 (diff) | |
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>
Diffstat (limited to 'isisd')
| -rw-r--r-- | isisd/isis_adjacency.c | 40 | ||||
| -rw-r--r-- | isisd/isis_adjacency.h | 1 | ||||
| -rw-r--r-- | isisd/isis_circuit.c | 21 | ||||
| -rw-r--r-- | isisd/isis_circuit.h | 4 | ||||
| -rw-r--r-- | isisd/isis_route.c | 50 | ||||
| -rw-r--r-- | isisd/isis_route.h | 5 | ||||
| -rw-r--r-- | isisd/isis_spf.c | 9 | ||||
| -rw-r--r-- | isisd/isis_spf.h | 4 | ||||
| -rw-r--r-- | isisd/isisd.c | 19 | ||||
| -rw-r--r-- | isisd/isisd.h | 3 | 
10 files changed, 155 insertions, 1 deletions
diff --git a/isisd/isis_adjacency.c b/isisd/isis_adjacency.c index 11f17ec7bf..5b32a9e388 100644 --- a/isisd/isis_adjacency.c +++ b/isisd/isis_adjacency.c @@ -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,16 @@ 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); diff --git a/isisd/isis_adjacency.h b/isisd/isis_adjacency.h index 7467a619cb..49adc89ae5 100644 --- a/isisd/isis_adjacency.h +++ b/isisd/isis_adjacency.h @@ -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 */ diff --git a/isisd/isis_circuit.c b/isisd/isis_circuit.c index fedceed3bb..3bbdaac649 100644 --- a/isisd/isis_circuit.c +++ b/isisd/isis_circuit.c @@ -604,6 +604,27 @@ 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 = 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); diff --git a/isisd/isis_circuit.h b/isisd/isis_circuit.h index 5ff0390c26..db8e2f752a 100644 --- a/isisd/isis_circuit.h +++ b/isisd/isis_circuit.h @@ -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, diff --git a/isisd/isis_route.c b/isisd/isis_route.c index 9f8f639e5d..b04e8e4553 100644 --- a/isisd/isis_route.c +++ b/isisd/isis_route.c @@ -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); +	} +} diff --git a/isisd/isis_route.h b/isisd/isis_route.h index 0e206d08f4..a0e0500aec 100644 --- a/isisd/isis_route.h +++ b/isisd/isis_route.h @@ -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 */ diff --git a/isisd/isis_spf.c b/isisd/isis_spf.c index 49c62d2cf5..d82925536e 100644 --- a/isisd/isis_spf.c +++ b/isisd/isis_spf.c @@ -1860,6 +1860,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); diff --git a/isisd/isis_spf.h b/isisd/isis_spf.h index 815db7b226..3fa5182baf 100644 --- a/isisd/isis_spf.h +++ b/isisd/isis_spf.h @@ -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); diff --git a/isisd/isisd.c b/isisd/isisd.c index 996a62f4d5..3a1eff0335 100644 --- a/isisd/isisd.c +++ b/isisd/isisd.c @@ -3077,6 +3077,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); diff --git a/isisd/isisd.h b/isisd/isisd.h index c313fd9ef7..a3dbfde6bc 100644 --- a/isisd/isisd.h +++ b/isisd/isisd.h @@ -287,6 +287,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_attached_bit_send_set(struct isis_area *area, bool attached_bit);  | 
