diff options
| -rw-r--r-- | isisd/isis_route.c | 147 | ||||
| -rw-r--r-- | isisd/isis_route.h | 16 | ||||
| -rw-r--r-- | isisd/isis_spf.c | 45 | ||||
| -rw-r--r-- | isisd/isis_spf.h | 3 | ||||
| -rw-r--r-- | isisd/isisd.c | 64 | ||||
| -rw-r--r-- | isisd/isisd.h | 5 | 
6 files changed, 111 insertions, 169 deletions
diff --git a/isisd/isis_route.c b/isisd/isis_route.c index c98e16e2bd..b6fb90b6dd 100644 --- a/isisd/isis_route.c +++ b/isisd/isis_route.c @@ -320,7 +320,8 @@ static int isis_route_info_same(struct isis_route_info *new,  struct isis_route_info *isis_route_create(struct prefix *prefix, uint32_t cost,  					  uint32_t depth,  					  struct list *adjacencies, -					  struct isis_area *area, int level) +					  struct isis_area *area, +					  struct route_table *table)  {  	struct route_node *route_node;  	struct isis_route_info *rinfo_new, *rinfo_old, *route_info = NULL; @@ -331,18 +332,11 @@ struct isis_route_info *isis_route_create(struct prefix *prefix, uint32_t cost,  	/* for debugs */  	prefix2str(prefix, buff, sizeof(buff)); -	rinfo_new = isis_route_info_new(prefix, cost, depth, adjacencies); - -	if (family == AF_INET) -		route_node = -			route_node_get(area->route_table[level - 1], prefix); -	else if (family == AF_INET6) -		route_node = -			route_node_get(area->route_table6[level - 1], prefix); -	else { -		isis_route_info_delete(rinfo_new); +	if (!table)  		return NULL; -	} + +	rinfo_new = isis_route_info_new(prefix, cost, depth, adjacencies); +	route_node = route_node_get(table, prefix);  	rinfo_old = route_node->info;  	if (!rinfo_old) { @@ -411,9 +405,9 @@ static void isis_route_delete(struct prefix *prefix, struct route_table *table)  	return;  } -/* Validating routes in particular table. */ -static void isis_route_validate_table(struct isis_area *area, -				      struct route_table *table) +static void _isis_route_verify_table(struct isis_area *area, +				     struct route_table *table, +				     struct route_table **tables)  {  	struct route_node *rnode, *drnode;  	struct isis_route_info *rinfo; @@ -448,36 +442,17 @@ static void isis_route_validate_table(struct isis_area *area,  			/* Area is either L1 or L2 => we use level route tables  			 * directly for  			 * validating => no problems with deleting routes. */ -			if (area->is_type != IS_LEVEL_1_AND_2) { +			if (!tables) {  				isis_route_delete(&rnode->p, table);  				continue;  			} +  			/* If area is L1L2, we work with merge table and  			 * therefore must  			 * delete node from level tables as well before deleting -			 * route info. -			 * FIXME: Is it performance problem? There has to be the -			 * better way. -			 * Like not to deal with it here at all (see the next -			 * comment)? */ -			if (rnode->p.family == AF_INET) { -				drnode = route_node_get(area->route_table[0], -							&rnode->p); -				if (drnode->info == rnode->info) -					drnode->info = NULL; -				drnode = route_node_get(area->route_table[1], -							&rnode->p); -				if (drnode->info == rnode->info) -					drnode->info = NULL; -			} - -			if (rnode->p.family == AF_INET6) { -				drnode = route_node_get(area->route_table6[0], -							&rnode->p); -				if (drnode->info == rnode->info) -					drnode->info = NULL; -				drnode = route_node_get(area->route_table6[1], -							&rnode->p); +			 * route info. */ +			for (int level = ISIS_LEVEL1; level <= ISIS_LEVEL2; level++) { +				drnode = route_node_get(tables[level - 1], &rnode->p);  				if (drnode->info == rnode->info)  					drnode->info = NULL;  			} @@ -487,6 +462,11 @@ static void isis_route_validate_table(struct isis_area *area,  	}  } +void isis_route_verify_table(struct isis_area *area, struct route_table *table) +{ +	return _isis_route_verify_table(area, table, NULL); +} +  /* Function to validate route tables for L1L2 areas. In this case we can't use   * level route tables directly, we have to merge them at first. L1 routes are   * preferred over the L2 ones. @@ -497,81 +477,34 @@ static void isis_route_validate_table(struct isis_area *area,   *   * FIXME: Is it right place to do it at all? Maybe we should push both levels   * to the RIB with different zebra route types and let RIB handle this? */ -static void isis_route_validate_merge(struct isis_area *area, int family) +void isis_route_verify_merge(struct isis_area *area, +			     struct route_table *level1_table, +			     struct route_table *level2_table)  { -	struct route_table *table = NULL; +	struct route_table *tables[] = { level1_table, level2_table };  	struct route_table *merge;  	struct route_node *rnode, *mrnode;  	merge = route_table_init(); -	if (family == AF_INET) -		table = area->route_table[0]; -	else if (family == AF_INET6) -		table = area->route_table6[0]; -	else { -		zlog_warn("ISIS-Rte (%s) %s called for unknown family %d", -			  area->area_tag, __func__, family); -		route_table_finish(merge); -		return; -	} - -	for (rnode = route_top(table); rnode; rnode = route_next(rnode)) { -		if (rnode->info == NULL) -			continue; -		mrnode = route_node_get(merge, &rnode->p); -		mrnode->info = rnode->info; -	} - -	if (family == AF_INET) -		table = area->route_table[1]; -	else if (family == AF_INET6) -		table = area->route_table6[1]; - -	for (rnode = route_top(table); rnode; rnode = route_next(rnode)) { -		if (rnode->info == NULL) -			continue; -		mrnode = route_node_get(merge, &rnode->p); -		if (mrnode->info != NULL) -			continue; -		mrnode->info = rnode->info; +	for (int level = ISIS_LEVEL1; level <= ISIS_LEVEL2; level++) { +		for (rnode = route_top(tables[level - 1]); rnode; +		     rnode = route_next(rnode)) { +			if (rnode->info == NULL) +				continue; +			mrnode = route_node_get(merge, &rnode->p); +			if (mrnode->info != NULL) { +				route_unlock_node(mrnode); +				continue; +			} +			mrnode->info = rnode->info; +		}  	} -	isis_route_validate_table(area, merge); +	_isis_route_verify_table(area, merge, tables);  	route_table_finish(merge);  } -/* Walk through route tables and propagate necessary changes into RIB. In case - * of L1L2 area, level tables have to be merged at first. */ -void isis_route_validate(struct isis_area *area) -{ -	struct listnode *node; -	struct isis_circuit *circuit; - -	if (area->is_type == IS_LEVEL_1) -		isis_route_validate_table(area, area->route_table[0]); -	else if (area->is_type == IS_LEVEL_2) -		isis_route_validate_table(area, area->route_table[1]); -	else -		isis_route_validate_merge(area, AF_INET); - -	if (area->is_type == IS_LEVEL_1) -		isis_route_validate_table(area, area->route_table6[0]); -	else if (area->is_type == IS_LEVEL_2) -		isis_route_validate_table(area, area->route_table6[1]); -	else -		isis_route_validate_merge(area, AF_INET6); - -	if (!area->circuit_list) { -		return; -	} -	/* walk all circuits and reset any spf specific flags */ -	for (ALL_LIST_ELEMENTS_RO(area->circuit_list, node, circuit)) -		UNSET_FLAG(circuit->flags, ISIS_CIRCUIT_FLAPPED_AFTER_SPF); - -	return; -} -  void isis_route_invalidate_table(struct isis_area *area,  				 struct route_table *table)  { @@ -585,11 +518,3 @@ void isis_route_invalidate_table(struct isis_area *area,  		UNSET_FLAG(rinfo->flag, ISIS_ROUTE_FLAG_ACTIVE);  	}  } - -void isis_route_invalidate(struct isis_area *area) -{ -	if (area->is_type & IS_LEVEL_1) -		isis_route_invalidate_table(area, area->route_table[0]); -	if (area->is_type & IS_LEVEL_2) -		isis_route_invalidate_table(area, area->route_table[1]); -} diff --git a/isisd/isis_route.h b/isisd/isis_route.h index 82f37c29f2..ae4b855cc7 100644 --- a/isisd/isis_route.h +++ b/isisd/isis_route.h @@ -53,11 +53,21 @@ struct isis_route_info {  struct isis_route_info *isis_route_create(struct prefix *prefix, uint32_t cost,  					  uint32_t depth,  					  struct list *adjacencies, -					  struct isis_area *area, int level); +					  struct isis_area *area, +					  struct route_table *table); -void isis_route_validate(struct isis_area *area); +/* Walk the given table and install new routes to zebra and remove old ones. + * route status is tracked using ISIS_ROUTE_FLAG_ACTIVE */ +void isis_route_verify_table(struct isis_area *area, +			     struct route_table *table); + +/* Same as isis_route_verify_table, but merge L1 and L2 routes before */ +void isis_route_verify_merge(struct isis_area *area, +			     struct route_table *level1_table, +			     struct route_table *level2_table); + +/* Unset ISIS_ROUTE_FLAG_ACTIVE on all routes. Used before running spf. */  void isis_route_invalidate_table(struct isis_area *area,  				 struct route_table *table); -void isis_route_invalidate(struct isis_area *area);  #endif /* _ZEBRA_ISIS_ROUTE_H */ diff --git a/isisd/isis_spf.c b/isisd/isis_spf.c index 556f2890cf..13be8bac53 100644 --- a/isisd/isis_spf.c +++ b/isisd/isis_spf.c @@ -275,6 +275,7 @@ static void isis_vertex_queue_delete(struct isis_vertex_queue *queue,  struct isis_spftree {  	struct isis_vertex_queue paths; /* the SPT */  	struct isis_vertex_queue tents; /* TENT */ +	struct route_table *route_table;  	struct isis_area *area;    /* back pointer to area */  	unsigned int runcount;     /* number of runs since uptime */  	time_t last_run_timestamp; /* last run timestamp as wall time for display */ @@ -472,6 +473,7 @@ struct isis_spftree *isis_spftree_new(struct isis_area *area)  	isis_vertex_queue_init(&tree->tents, "IS-IS SPF tents", true);  	isis_vertex_queue_init(&tree->paths, "IS-IS SPF paths", false); +	tree->route_table = route_table_init();  	tree->area = area;  	tree->last_run_timestamp = 0;  	tree->last_run_monotime = 0; @@ -484,8 +486,10 @@ void isis_spftree_del(struct isis_spftree *spftree)  {  	isis_vertex_queue_free(&spftree->tents);  	isis_vertex_queue_free(&spftree->paths); -	XFREE(MTYPE_ISIS_SPFTREE, spftree); +	route_table_finish(spftree->route_table); +	spftree->route_table = NULL; +	XFREE(MTYPE_ISIS_SPFTREE, spftree);  	return;  } @@ -1228,7 +1232,7 @@ static void add_to_paths(struct isis_spftree *spftree,  			isis_route_create((struct prefix *)&vertex->N.prefix,  					  vertex->d_N, vertex->depth,  					  vertex->Adj_N, spftree->area, -					  spftree->level); +					  spftree->route_table);  		else if (isis->debugs & DEBUG_SPF_EVENTS)  			zlog_debug(  				"ISIS-Spf: no adjacencies do not install route for " @@ -1261,7 +1265,6 @@ static int isis_run_spf(struct isis_area *area, int level, int family,  	struct isis_spftree *spftree = NULL;  	uint8_t lsp_id[ISIS_SYS_ID_LEN + 2];  	struct isis_lsp *lsp; -	struct route_table *table = NULL;  	struct timeval time_now;  	unsigned long long start_time, end_time;  	uint16_t mtid; @@ -1277,14 +1280,6 @@ static int isis_run_spf(struct isis_area *area, int level, int family,  	assert(spftree);  	assert(sysid); -	/* Make all routes in current route table inactive. */ -	if (family == AF_INET) -		table = area->route_table[level - 1]; -	else if (family == AF_INET6) -		table = area->route_table6[level - 1]; - -	isis_route_invalidate_table(area, table); -  	/* We only support ipv4-unicast and ipv6-unicast as topologies for now  	 */  	if (family == AF_INET6) @@ -1342,7 +1337,6 @@ static int isis_run_spf(struct isis_area *area, int level, int family,  	}  out: -	isis_route_validate(area);  	spftree->runcount++;  	spftree->last_run_timestamp = time(NULL);  	spftree->last_run_monotime = monotime(&time_now); @@ -1353,6 +1347,23 @@ out:  	return retval;  } +void isis_spf_verify_routes(struct isis_area *area, struct isis_spftree **trees) +{ +	if (area->is_type == IS_LEVEL_1) { +		isis_route_verify_table(area, trees[0]->route_table); +	} else if (area->is_type == IS_LEVEL_2) { +		isis_route_verify_table(area, trees[1]->route_table); +	} else { +		isis_route_verify_merge(area, trees[0]->route_table, +					trees[1]->route_table); +	} +} + +void isis_spf_invalidate_routes(struct isis_spftree *tree) +{ +	isis_route_invalidate_table(tree->area, tree->route_table); +} +  static int isis_run_spf_cb(struct thread *thread)  {  	struct isis_spf_run *run = THREAD_ARG(thread); @@ -1370,6 +1381,8 @@ static int isis_run_spf_cb(struct thread *thread)  		return ISIS_WARNING;  	} +	isis_area_invalidate_routes(area, level); +  	if (isis->debugs & DEBUG_SPF_EVENTS)  		zlog_debug("ISIS-Spf (%s) L%d SPF needed, periodic SPF",  			   area->area_tag, level); @@ -1381,6 +1394,14 @@ static int isis_run_spf_cb(struct thread *thread)  		retval = isis_run_spf(area, level, AF_INET6, isis->sysid,  				      &thread->real); +	isis_area_verify_routes(area); + +	/* walk all circuits and reset any spf specific flags */ +	struct listnode *node; +	struct isis_circuit *circuit; +	for (ALL_LIST_ELEMENTS_RO(area->circuit_list, node, circuit)) +		UNSET_FLAG(circuit->flags, ISIS_CIRCUIT_FLAPPED_AFTER_SPF); +  	return retval;  } diff --git a/isisd/isis_spf.h b/isisd/isis_spf.h index 84e07861d2..9a73ca8783 100644 --- a/isisd/isis_spf.h +++ b/isisd/isis_spf.h @@ -27,6 +27,9 @@  struct isis_spftree;  struct isis_spftree *isis_spftree_new(struct isis_area *area); +void isis_spf_invalidate_routes(struct isis_spftree *tree); +void isis_spf_verify_routes(struct isis_area *area, +			    struct isis_spftree **trees);  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 cecaa0693d..0094b30c28 100644 --- a/isisd/isisd.c +++ b/isisd/isisd.c @@ -118,13 +118,9 @@ struct isis_area *isis_area_create(const char *area_tag)  	 */  	if (area->is_type & IS_LEVEL_1) {  		area->lspdb[0] = lsp_db_init(); -		area->route_table[0] = route_table_init(); -		area->route_table6[0] = route_table_init();  	}  	if (area->is_type & IS_LEVEL_2) {  		area->lspdb[1] = lsp_db_init(); -		area->route_table[1] = route_table_init(); -		area->route_table6[1] = route_table_init();  	}  	spftree_area_init(area); @@ -232,6 +228,10 @@ int isis_area_destroy(struct vty *vty, const char *area_tag)  		area->lspdb[1] = NULL;  	} +	/* invalidate and verify to delete all routes from zebra */ +	isis_area_invalidate_routes(area, ISIS_LEVEL1 & ISIS_LEVEL2); +	isis_area_verify_routes(area); +  	spftree_area_del(area);  	THREAD_TIMER_OFF(area->spf_timer[0]); @@ -240,27 +240,6 @@ int isis_area_destroy(struct vty *vty, const char *area_tag)  	spf_backoff_free(area->spf_delay_ietf[0]);  	spf_backoff_free(area->spf_delay_ietf[1]); -	/* invalidate and validate would delete all routes from zebra */ -	isis_route_invalidate(area); -	isis_route_validate(area); - -	if (area->route_table[0]) { -		route_table_finish(area->route_table[0]); -		area->route_table[0] = NULL; -	} -	if (area->route_table[1]) { -		route_table_finish(area->route_table[1]); -		area->route_table[1] = NULL; -	} -	if (area->route_table6[0]) { -		route_table_finish(area->route_table6[0]); -		area->route_table6[0] = NULL; -	} -	if (area->route_table6[1]) { -		route_table_finish(area->route_table6[1]); -		area->route_table6[1] = NULL; -	} -  	isis_redist_area_finish(area);  	for (ALL_LIST_ELEMENTS(area->area_addrs, node, nnode, addr)) { @@ -1680,8 +1659,27 @@ int isis_area_passwd_hmac_md5_set(struct isis_area *area, int level,  				    passwd, snp_auth);  } +void isis_area_invalidate_routes(struct isis_area *area, int levels) +{ +	for (int level = ISIS_LEVEL1; level <= ISIS_LEVEL2; level++) { +		if (!(level & levels)) +			continue; +		isis_spf_invalidate_routes(area->spftree[level - 1]); +		isis_spf_invalidate_routes(area->spftree6[level - 1]); +	} +} + +void isis_area_verify_routes(struct isis_area *area) +{ +	isis_spf_verify_routes(area, area->spftree); +	isis_spf_verify_routes(area, area->spftree6); +} +  static void area_resign_level(struct isis_area *area, int level)  { +	isis_area_invalidate_routes(area, level); +	isis_area_verify_routes(area); +  	if (area->lspdb[level - 1]) {  		lsp_db_destroy(area->lspdb[level - 1]);  		area->lspdb[level - 1] = NULL; @@ -1695,14 +1693,6 @@ static void area_resign_level(struct isis_area *area, int level)  		area->spftree6[level - 1] = NULL;  	}  	THREAD_TIMER_OFF(area->spf_timer[level - 1]); -	if (area->route_table[level - 1]) { -		route_table_finish(area->route_table[level - 1]); -		area->route_table[level - 1] = NULL; -	} -	if (area->route_table6[level - 1]) { -		route_table_finish(area->route_table6[level - 1]); -		area->route_table6[level - 1] = NULL; -	}  	sched_debug(  		"ISIS (%s): Resigned from L%d - canceling LSP regeneration timer.", @@ -1731,10 +1721,6 @@ void isis_area_is_type_set(struct isis_area *area, int is_type)  		if (area->lspdb[1] == NULL)  			area->lspdb[1] = lsp_db_init(); -		if (area->route_table[1] == NULL) -			area->route_table[1] = route_table_init(); -		if (area->route_table6[1] == NULL) -			area->route_table6[1] = route_table_init();  		break;  	case IS_LEVEL_1_AND_2: @@ -1750,10 +1736,6 @@ void isis_area_is_type_set(struct isis_area *area, int is_type)  		if (area->lspdb[0] == NULL)  			area->lspdb[0] = lsp_db_init(); -		if (area->route_table[0] == NULL) -			area->route_table[0] = route_table_init(); -		if (area->route_table6[0] == NULL) -			area->route_table6[0] = route_table_init();  		break;  	default: diff --git a/isisd/isisd.h b/isisd/isisd.h index d1ad9f3b8e..c1bf6bc976 100644 --- a/isisd/isisd.h +++ b/isisd/isisd.h @@ -67,9 +67,7 @@ struct isis_area {  	struct isis *isis;			       /* back pointer */  	dict_t *lspdb[ISIS_LEVELS];		       /* link-state dbs */  	struct isis_spftree *spftree[ISIS_LEVELS];     /* The v4 SPTs */ -	struct route_table *route_table[ISIS_LEVELS];  /* IPv4 routes */  	struct isis_spftree *spftree6[ISIS_LEVELS];    /* The v6 SPTs */ -	struct route_table *route_table6[ISIS_LEVELS]; /* IPv6 routes */  #define DEFAULT_LSP_MTU 1497  	unsigned int lsp_mtu;      /* Size of LSPs to generate */  	struct list *circuit_list; /* IS-IS circuits */ @@ -144,6 +142,9 @@ struct isis_area *isis_area_lookup(const char *);  int isis_area_get(struct vty *vty, const char *area_tag);  void print_debug(struct vty *, int, int); +void isis_area_invalidate_routes(struct isis_area *area, int levels); +void isis_area_verify_routes(struct isis_area *area); +  void isis_area_overload_bit_set(struct isis_area *area, bool overload_bit);  void isis_area_attached_bit_set(struct isis_area *area, bool attached_bit);  void isis_area_dynhostname_set(struct isis_area *area, bool dynhostname);  | 
