isisd: fix refcounting in isis_route.c

This fixes multiple issues and inefficiencies regarding the usage of
route_tables in isis_route.c and removes some memory leaks.

Signed-off-by: Christian Franke <chris@opensourcerouting.org>
This commit is contained in:
Christian Franke 2018-08-01 13:23:56 +02:00
parent 321c1bbb94
commit bcd9fd5011

View File

@ -353,6 +353,7 @@ struct isis_route_info *isis_route_create(struct prefix *prefix,
route_info = rinfo_new;
UNSET_FLAG(route_info->flag, ISIS_ROUTE_FLAG_ZEBRA_SYNCED);
} else {
route_unlock_node(route_node);
if (isis->debugs & DEBUG_RTE_EVENTS)
zlog_debug("ISIS-Rte (%s) route already exists: %s",
area->area_tag, buff);
@ -379,20 +380,21 @@ struct isis_route_info *isis_route_create(struct prefix *prefix,
return route_info;
}
static void isis_route_delete(struct prefix *prefix,
struct prefix_ipv6 *src_p,
static void isis_route_delete(struct route_node *rode,
struct route_table *table)
{
struct route_node *rode;
struct isis_route_info *rinfo;
char buff[SRCDEST2STR_BUFFER];
struct prefix *prefix;
struct prefix_ipv6 *src_p;
/* for log */
srcdest2str(prefix, src_p, buff, sizeof(buff));
srcdest_rnode2str(rode, buff, sizeof(buff));
srcdest_rnode_prefixes(rode, (const struct prefix **)&prefix,
(const struct prefix **)&src_p);
rode = srcdest_rnode_get(table, prefix, src_p);
rinfo = rode->info;
if (rinfo == NULL) {
if (isis->debugs & DEBUG_RTE_EVENTS)
zlog_debug(
@ -409,8 +411,7 @@ static void isis_route_delete(struct prefix *prefix,
}
isis_route_info_delete(rinfo);
rode->info = NULL;
return;
route_unlock_node(rode);
}
static void _isis_route_verify_table(struct isis_area *area,
@ -454,28 +455,38 @@ static void _isis_route_verify_table(struct isis_area *area,
}
isis_zebra_route_update(dst_p, src_p, rinfo);
if (!CHECK_FLAG(rinfo->flag, ISIS_ROUTE_FLAG_ACTIVE)) {
/* Area is either L1 or L2 => we use level route tables
* directly for
* validating => no problems with deleting routes. */
if (!tables) {
isis_route_delete(dst_p, src_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. */
for (int level = ISIS_LEVEL1; level <= ISIS_LEVEL2; level++) {
drnode = srcdest_rnode_get(tables[level - 1],
dst_p, src_p);
if (drnode->info == rnode->info)
drnode->info = NULL;
}
if (CHECK_FLAG(rinfo->flag, ISIS_ROUTE_FLAG_ACTIVE))
continue;
isis_route_delete(dst_p, src_p, table);
/* Area is either L1 or L2 => we use level route tables
* directly for
* validating => no problems with deleting routes. */
if (!tables) {
isis_route_delete(rnode, 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. */
for (int level = ISIS_LEVEL1; level <= ISIS_LEVEL2; level++) {
drnode = srcdest_rnode_lookup(tables[level - 1],
dst_p, src_p);
if (!drnode)
continue;
route_unlock_node(drnode);
if (drnode->info != rnode->info)
continue;
drnode->info = NULL;
route_unlock_node(drnode);
}
isis_route_delete(rnode, table);
}
}