From 8fc9e007ee752a982fe47311702d7ff3b9c5b5cd Mon Sep 17 00:00:00 2001 From: JR Rivers Date: Mon, 24 Sep 2012 17:26:46 +0000 Subject: ospfd: blackhole route removal for area range ISSUE When an area range is created in which there the sub-area has routes that are smaller than the range, an ABR creates a blackhole route to cover the range. When the range is removed, the blackhole route is not removed. --A----B----C--- B is an ABR with A in area 1 and C in area 0. If A advertises `10.2.0.0/30` and `10.2.0.4/30` and B is configured with `area 0.0.0.1 range 10.2.0.0/29` a blackhole is created on B (`blackhole 10.2.0.0/29 proto zebra`). When the area/range is removed via the command line, the blackhole remains in existence even though the "range" route is removed from area 0 and the individual routes are propagated. PATCH The reason for this behavior is that, prior to this patch, the range is deleted from the area's list, so when ospf_abr_manage_discard_routes() gets called, there is nothing to clean up. The patch removes the discard route as part of the processing of the command line (ospf_area_range_unset()). Signed-off-by: JR Rivers Signed-off-by: Scott Feldman Reviewed-by: Shrijeet Mukherjee Signed-off-by: David Lamparter --- ospfd/ospf_abr.c | 36 ++++++++++++++++-------------------- ospfd/ospf_route.c | 50 +++++++++++++++++++++++++++++++++++++++++++++++++- ospfd/ospf_route.h | 2 +- 3 files changed, 66 insertions(+), 22 deletions(-) diff --git a/ospfd/ospf_abr.c b/ospfd/ospf_abr.c index b7cc20dd..ef1048b2 100644 --- a/ospfd/ospf_abr.c +++ b/ospfd/ospf_abr.c @@ -88,23 +88,18 @@ ospf_area_range_add (struct ospf_area *area, struct ospf_area_range *range) } static void -ospf_area_range_delete (struct ospf_area *area, struct ospf_area_range *range) +ospf_area_range_delete (struct ospf_area *area, struct route_node *rn) { - struct route_node *rn; - struct prefix_ipv4 p; + struct ospf_area_range *range = rn->info; - p.family = AF_INET; - p.prefixlen = range->masklen; - p.prefix = range->addr; + if (range->specifics != 0) + ospf_delete_discard_route (area->ospf->new_table, + (struct prefix_ipv4 *) &rn->p); - rn = route_node_lookup (area->ranges, (struct prefix *)&p); - if (rn) - { - ospf_area_range_free (rn->info); - rn->info = NULL; - route_unlock_node (rn); - route_unlock_node (rn); - } + ospf_area_range_free (range); + rn->info = NULL; + route_unlock_node (rn); + route_unlock_node (rn); } struct ospf_area_range * @@ -263,20 +258,20 @@ ospf_area_range_unset (struct ospf *ospf, struct in_addr area_id, struct prefix_ipv4 *p) { struct ospf_area *area; - struct ospf_area_range *range; + struct route_node *rn; area = ospf_area_lookup_by_area_id (ospf, area_id); if (area == NULL) return 0; - range = ospf_area_range_lookup (area, p); - if (range == NULL) + rn = route_node_lookup (area->ranges, (struct prefix*)p); + if (rn == NULL) return 0; - if (ospf_area_range_active (range)) + if (ospf_area_range_active (rn->info)) ospf_schedule_abr_task (ospf); - ospf_area_range_delete (area, range); + ospf_area_range_delete (area, rn); return 1; } @@ -1695,7 +1690,8 @@ ospf_abr_manage_discard_routes (struct ospf *ospf) ospf_add_discard_route (ospf->new_table, area, (struct prefix_ipv4 *) &rn->p); else - ospf_delete_discard_route ((struct prefix_ipv4 *) &rn->p); + ospf_delete_discard_route (ospf->new_table, + (struct prefix_ipv4 *) &rn->p); } } diff --git a/ospfd/ospf_route.c b/ospfd/ospf_route.c index a5d6d18c..c3acba34 100644 --- a/ospfd/ospf_route.c +++ b/ospfd/ospf_route.c @@ -954,6 +954,10 @@ ospf_add_discard_route (struct route_table *rt, struct ospf_area *area, ospf_route_free (rn->info); } + if (IS_DEBUG_OSPF_EVENT) + zlog_debug ("ospf_add_discard_route(): " + "adding %s/%d", inet_ntoa (p->prefix), p->prefixlen); + new_or = ospf_route_new (); new_or->type = OSPF_DESTINATION_DISCARD; new_or->id.s_addr = 0; @@ -969,8 +973,52 @@ ospf_add_discard_route (struct route_table *rt, struct ospf_area *area, } void -ospf_delete_discard_route (struct prefix_ipv4 *p) +ospf_delete_discard_route (struct route_table *rt, struct prefix_ipv4 *p) { + struct route_node *rn; + struct ospf_route *or; + + if (IS_DEBUG_OSPF_EVENT) + zlog_debug ("ospf_delete_discard_route(): " + "deleting %s/%d", inet_ntoa (p->prefix), p->prefixlen); + + rn = route_node_lookup (rt, (struct prefix*)p); + + if (rn == NULL) + { + if (IS_DEBUG_OSPF_EVENT) + zlog_debug("ospf_delete_discard_route(): no route found"); + return; + } + + or = rn->info; + + if (or->path_type == OSPF_PATH_INTRA_AREA) + { + if (IS_DEBUG_OSPF_EVENT) + zlog_debug ("ospf_delete_discard_route(): " + "an intra-area route exists"); + return; + } + + if (or->type != OSPF_DESTINATION_DISCARD) + { + if (IS_DEBUG_OSPF_EVENT) + zlog_debug ("ospf_delete_discard_route(): " + "not a discard entry"); + return; + } + + /* free the route entry and the route node */ + ospf_route_free (rn->info); + + rn->info = NULL; + route_unlock_node (rn); + route_unlock_node (rn); + + /* remove the discard entry from the rib */ ospf_zebra_delete_discard(p); + + return; } diff --git a/ospfd/ospf_route.h b/ospfd/ospf_route.h index 5742b462..6c202b0c 100644 --- a/ospfd/ospf_route.h +++ b/ospfd/ospf_route.h @@ -159,7 +159,7 @@ extern void ospf_prune_unreachable_networks (struct route_table *); extern void ospf_prune_unreachable_routers (struct route_table *); extern int ospf_add_discard_route (struct route_table *, struct ospf_area *, struct prefix_ipv4 *); -extern void ospf_delete_discard_route (struct prefix_ipv4 *); +extern void ospf_delete_discard_route (struct route_table *, struct prefix_ipv4 *); extern int ospf_route_match_same (struct route_table *, struct prefix_ipv4 *, struct ospf_route *); -- cgit v1.2.1