diff options
Diffstat (limited to 'ospfd/ospf_ia.c')
| -rw-r--r-- | ospfd/ospf_ia.c | 1222 | 
1 files changed, 607 insertions, 615 deletions
diff --git a/ospfd/ospf_ia.c b/ospfd/ospf_ia.c index ebd267ded9..c65d8b8743 100644 --- a/ospfd/ospf_ia.c +++ b/ospfd/ospf_ia.c @@ -45,670 +45,662 @@  #include "ospfd/ospf_ia.h"  #include "ospfd/ospf_dump.h" -static struct ospf_route * -ospf_find_abr_route (struct route_table *rtrs,  -                     struct prefix_ipv4 *abr, -                     struct ospf_area *area) +static struct ospf_route *ospf_find_abr_route(struct route_table *rtrs, +					      struct prefix_ipv4 *abr, +					      struct ospf_area *area)  { -  struct route_node *rn; -  struct ospf_route *or; -  struct listnode *node; +	struct route_node *rn; +	struct ospf_route * or ; +	struct listnode *node; -  if ((rn = route_node_lookup (rtrs, (struct prefix *) abr)) == NULL) -    return NULL; +	if ((rn = route_node_lookup(rtrs, (struct prefix *)abr)) == NULL) +		return NULL; -  route_unlock_node (rn); +	route_unlock_node(rn); -  for (ALL_LIST_ELEMENTS_RO ((struct list *) rn->info, node, or)) -    if (IPV4_ADDR_SAME (&or->u.std.area_id, &area->area_id)  -        && (or->u.std.flags & ROUTER_LSA_BORDER)) -      return or; +	for (ALL_LIST_ELEMENTS_RO((struct list *)rn->info, node, or)) +		if (IPV4_ADDR_SAME(& or->u.std.area_id, &area->area_id) +		    && (or->u.std.flags & ROUTER_LSA_BORDER)) +			return or ; -  return NULL; +	return NULL;  } -static void -ospf_ia_network_route (struct ospf *ospf, struct route_table *rt, -		       struct prefix_ipv4 *p, struct ospf_route *new_or, -		       struct ospf_route *abr_or) +static void ospf_ia_network_route(struct ospf *ospf, struct route_table *rt, +				  struct prefix_ipv4 *p, +				  struct ospf_route *new_or, +				  struct ospf_route *abr_or)  { -  struct route_node *rn1; -  struct ospf_route *or; - -  if (IS_DEBUG_OSPF_EVENT) -    zlog_debug ("ospf_ia_network_route(): processing summary route to %s/%d",  -	       inet_ntoa (p->prefix), p->prefixlen); - -  /* Find a route to the same dest */ -  if ((rn1 = route_node_lookup (rt, (struct prefix *) p))) -    { -      int res; - -      route_unlock_node (rn1); - -      if ((or = rn1->info)) -	{ -	  if (IS_DEBUG_OSPF_EVENT) -	    zlog_debug ("ospf_ia_network_route(): " -		       "Found a route to the same network"); -	  /* Check the existing route. */ -	  if ((res = ospf_route_cmp (ospf, new_or, or)) < 0) -	    { -	      /* New route is better, so replace old one. */ -	      ospf_route_subst (rn1, new_or, abr_or); -	    } -	  else if (res == 0) -	    { -	      /* New and old route are equal, so next hops can be added. */ -	      route_lock_node (rn1); -	      ospf_route_copy_nexthops (or, abr_or->paths); -	      route_unlock_node (rn1); - -	      /* new route can be deleted, because existing route has been updated. */ -	      ospf_route_free (new_or); -	    } -	  else -	    { -	      /* New route is worse, so free it. */ -	      ospf_route_free (new_or); -	      return; -	    } -	} /* if (or)*/ -    } /*if (rn1)*/ -  else -    { /* no route */ -      if (IS_DEBUG_OSPF_EVENT) -	zlog_debug ("ospf_ia_network_route(): add new route to %s/%d", -		   inet_ntoa (p->prefix), p->prefixlen); -      ospf_route_add (rt, p, new_or, abr_or); -    } +	struct route_node *rn1; +	struct ospf_route * or ; + +	if (IS_DEBUG_OSPF_EVENT) +		zlog_debug( +			"ospf_ia_network_route(): processing summary route to %s/%d", +			inet_ntoa(p->prefix), p->prefixlen); + +	/* Find a route to the same dest */ +	if ((rn1 = route_node_lookup(rt, (struct prefix *)p))) { +		int res; + +		route_unlock_node(rn1); + +		if ((or = rn1->info)) { +			if (IS_DEBUG_OSPF_EVENT) +				zlog_debug( +					"ospf_ia_network_route(): " +					"Found a route to the same network"); +			/* Check the existing route. */ +			if ((res = ospf_route_cmp(ospf, new_or, or)) < 0) { +				/* New route is better, so replace old one. */ +				ospf_route_subst(rn1, new_or, abr_or); +			} else if (res == 0) { +				/* New and old route are equal, so next hops can +				 * be added. */ +				route_lock_node(rn1); +				ospf_route_copy_nexthops(or, abr_or->paths); +				route_unlock_node(rn1); + +				/* new route can be deleted, because existing +				 * route has been updated. */ +				ospf_route_free(new_or); +			} else { +				/* New route is worse, so free it. */ +				ospf_route_free(new_or); +				return; +			} +		} /* if (or)*/ +	}	 /*if (rn1)*/ +	else {    /* no route */ +		if (IS_DEBUG_OSPF_EVENT) +			zlog_debug( +				"ospf_ia_network_route(): add new route to %s/%d", +				inet_ntoa(p->prefix), p->prefixlen); +		ospf_route_add(rt, p, new_or, abr_or); +	}  } -static void -ospf_ia_router_route (struct ospf *ospf, struct route_table *rtrs, -		      struct prefix_ipv4 *p, -                      struct ospf_route *new_or, struct ospf_route *abr_or) +static void ospf_ia_router_route(struct ospf *ospf, struct route_table *rtrs, +				 struct prefix_ipv4 *p, +				 struct ospf_route *new_or, +				 struct ospf_route *abr_or)  { -  struct ospf_route *or = NULL; -  struct route_node *rn; -  int ret; - -  if (IS_DEBUG_OSPF_EVENT) -    zlog_debug ("ospf_ia_router_route(): considering %s/%d",  -	       inet_ntoa (p->prefix), p->prefixlen); -  /* Find a route to the same dest */ -  rn = route_node_get (rtrs, (struct prefix *) p); -    -  if (rn->info == NULL) -    /* This is a new route */ -    rn->info = list_new (); -  else -    { -      struct ospf_area *or_area; -      or_area = ospf_area_lookup_by_area_id (ospf, new_or->u.std.area_id); -      assert (or_area); -      /* This is an additional route */ -      route_unlock_node (rn); -      or = ospf_find_asbr_route_through_area (rtrs, p, or_area); -    } - -  if (or) -    { -      if (IS_DEBUG_OSPF_EVENT) -	zlog_debug ("ospf_ia_router_route(): " -		   "a route to the same ABR through the same area exists"); -      /* New route is better */ -      if ((ret = ospf_route_cmp (ospf, new_or, or)) < 0) -	{ -	  listnode_delete (rn->info, or); -	  ospf_route_free (or); -	  /* proceed down */ +	struct ospf_route * or = NULL; +	struct route_node *rn; +	int ret; + +	if (IS_DEBUG_OSPF_EVENT) +		zlog_debug("ospf_ia_router_route(): considering %s/%d", +			   inet_ntoa(p->prefix), p->prefixlen); +	/* Find a route to the same dest */ +	rn = route_node_get(rtrs, (struct prefix *)p); + +	if (rn->info == NULL) +		/* This is a new route */ +		rn->info = list_new(); +	else { +		struct ospf_area *or_area; +		or_area = ospf_area_lookup_by_area_id(ospf, +						      new_or->u.std.area_id); +		assert(or_area); +		/* This is an additional route */ +		route_unlock_node(rn); +		or = ospf_find_asbr_route_through_area(rtrs, p, or_area);  	} -      /* Routes are the same */ -      else if (ret == 0) -	{ -	  if (IS_DEBUG_OSPF_EVENT) -	    zlog_debug ("ospf_ia_router_route(): merging the new route"); -	  ospf_route_copy_nexthops (or, abr_or->paths); -	  ospf_route_free (new_or); -	  return; -	} -      /* New route is worse */ -      else -	{ -	  if (IS_DEBUG_OSPF_EVENT) -	    zlog_debug ("ospf_ia_router_route(): skipping the new route"); -	  ospf_route_free (new_or); -	  return; +	if (or) { +		if (IS_DEBUG_OSPF_EVENT) +			zlog_debug( +				"ospf_ia_router_route(): " +				"a route to the same ABR through the same area exists"); +		/* New route is better */ +		if ((ret = ospf_route_cmp(ospf, new_or, or)) < 0) { +			listnode_delete(rn->info, or); +			ospf_route_free(or); +			/* proceed down */ +		} +		/* Routes are the same */ +		else if (ret == 0) { +			if (IS_DEBUG_OSPF_EVENT) +				zlog_debug( +					"ospf_ia_router_route(): merging the new route"); + +			ospf_route_copy_nexthops(or, abr_or->paths); +			ospf_route_free(new_or); +			return; +		} +		/* New route is worse */ +		else { +			if (IS_DEBUG_OSPF_EVENT) +				zlog_debug( +					"ospf_ia_router_route(): skipping the new route"); +			ospf_route_free(new_or); +			return; +		}  	} -    } -  ospf_route_copy_nexthops (new_or, abr_or->paths); +	ospf_route_copy_nexthops(new_or, abr_or->paths); -  if (IS_DEBUG_OSPF_EVENT) -    zlog_debug ("ospf_ia_router_route(): adding the new route");  +	if (IS_DEBUG_OSPF_EVENT) +		zlog_debug("ospf_ia_router_route(): adding the new route"); -  listnode_add (rn->info, new_or); +	listnode_add(rn->info, new_or);  } -static int -process_summary_lsa (struct ospf_area *area, struct route_table *rt, -		     struct route_table *rtrs, struct ospf_lsa *lsa) +static int process_summary_lsa(struct ospf_area *area, struct route_table *rt, +			       struct route_table *rtrs, struct ospf_lsa *lsa)  { -  struct ospf *ospf = area->ospf; -  struct ospf_area_range *range; -  struct ospf_route *abr_or, *new_or; -  struct summary_lsa *sl; -  struct prefix_ipv4 p, abr; -  u_int32_t metric; - -  if (lsa == NULL) -    return 0; - -  sl = (struct summary_lsa *) lsa->data; - -  if (IS_DEBUG_OSPF_EVENT) -    zlog_debug ("process_summary_lsa(): LS ID: %s", inet_ntoa (sl->header.id)); - -  metric = GET_METRIC (sl->metric); -    -  if (metric == OSPF_LS_INFINITY) -    return 0; - -  if (IS_LSA_MAXAGE (lsa)) -    return 0; - -  if (ospf_lsa_is_self_originated (area->ospf, lsa)) -    return 0; - -  p.family = AF_INET; -  p.prefix = sl->header.id; -    -  if (sl->header.type == OSPF_SUMMARY_LSA) -    p.prefixlen = ip_masklen (sl->mask); -  else -    p.prefixlen = IPV4_MAX_BITLEN; -       -  apply_mask_ipv4 (&p); - -  if (sl->header.type == OSPF_SUMMARY_LSA && -      (range = ospf_area_range_match_any (ospf, &p)) && -      ospf_area_range_active (range)) -    return 0; - -  /* XXX: This check seems dubious to me. If an ABR has already decided -   * to consider summaries received in this area, then why would one wish -   * to exclude default?  -   */ -  if (IS_OSPF_ABR(ospf) &&  -      ospf->abr_type != OSPF_ABR_STAND && -      area->external_routing != OSPF_AREA_DEFAULT && -      p.prefix.s_addr == OSPF_DEFAULT_DESTINATION && -      p.prefixlen == 0) -    return 0; /* Ignore summary default from a stub area */ - -  abr.family = AF_INET; -  abr.prefix = sl->header.adv_router; -  abr.prefixlen = IPV4_MAX_BITLEN; -  apply_mask_ipv4 (&abr); - -  abr_or = ospf_find_abr_route (rtrs, &abr, area); - -  if (abr_or == NULL) -    return 0; - -  new_or = ospf_route_new (); -  new_or->type = OSPF_DESTINATION_NETWORK; -  new_or->id = sl->header.id; -  new_or->mask = sl->mask; -  new_or->u.std.options = sl->header.options; -  new_or->u.std.origin = (struct lsa_header *) sl; -  new_or->cost = abr_or->cost + metric; -  new_or->u.std.area_id = area->area_id; -  new_or->u.std.external_routing = area->external_routing; -  new_or->path_type = OSPF_PATH_INTER_AREA; - -  if (sl->header.type == OSPF_SUMMARY_LSA) -    ospf_ia_network_route (ospf, rt, &p, new_or, abr_or); -  else  -    { -      new_or->type = OSPF_DESTINATION_ROUTER; -      new_or->u.std.flags = ROUTER_LSA_EXTERNAL; -      ospf_ia_router_route (ospf, rtrs, &p, new_or, abr_or); -    } - -  return 0; +	struct ospf *ospf = area->ospf; +	struct ospf_area_range *range; +	struct ospf_route *abr_or, *new_or; +	struct summary_lsa *sl; +	struct prefix_ipv4 p, abr; +	u_int32_t metric; + +	if (lsa == NULL) +		return 0; + +	sl = (struct summary_lsa *)lsa->data; + +	if (IS_DEBUG_OSPF_EVENT) +		zlog_debug("process_summary_lsa(): LS ID: %s", +			   inet_ntoa(sl->header.id)); + +	metric = GET_METRIC(sl->metric); + +	if (metric == OSPF_LS_INFINITY) +		return 0; + +	if (IS_LSA_MAXAGE(lsa)) +		return 0; + +	if (ospf_lsa_is_self_originated(area->ospf, lsa)) +		return 0; + +	p.family = AF_INET; +	p.prefix = sl->header.id; + +	if (sl->header.type == OSPF_SUMMARY_LSA) +		p.prefixlen = ip_masklen(sl->mask); +	else +		p.prefixlen = IPV4_MAX_BITLEN; + +	apply_mask_ipv4(&p); + +	if (sl->header.type == OSPF_SUMMARY_LSA +	    && (range = ospf_area_range_match_any(ospf, &p)) +	    && ospf_area_range_active(range)) +		return 0; + +	/* XXX: This check seems dubious to me. If an ABR has already decided +	 * to consider summaries received in this area, then why would one wish +	 * to exclude default? +	 */ +	if (IS_OSPF_ABR(ospf) && ospf->abr_type != OSPF_ABR_STAND +	    && area->external_routing != OSPF_AREA_DEFAULT +	    && p.prefix.s_addr == OSPF_DEFAULT_DESTINATION && p.prefixlen == 0) +		return 0; /* Ignore summary default from a stub area */ + +	abr.family = AF_INET; +	abr.prefix = sl->header.adv_router; +	abr.prefixlen = IPV4_MAX_BITLEN; +	apply_mask_ipv4(&abr); + +	abr_or = ospf_find_abr_route(rtrs, &abr, area); + +	if (abr_or == NULL) +		return 0; + +	new_or = ospf_route_new(); +	new_or->type = OSPF_DESTINATION_NETWORK; +	new_or->id = sl->header.id; +	new_or->mask = sl->mask; +	new_or->u.std.options = sl->header.options; +	new_or->u.std.origin = (struct lsa_header *)sl; +	new_or->cost = abr_or->cost + metric; +	new_or->u.std.area_id = area->area_id; +	new_or->u.std.external_routing = area->external_routing; +	new_or->path_type = OSPF_PATH_INTER_AREA; + +	if (sl->header.type == OSPF_SUMMARY_LSA) +		ospf_ia_network_route(ospf, rt, &p, new_or, abr_or); +	else { +		new_or->type = OSPF_DESTINATION_ROUTER; +		new_or->u.std.flags = ROUTER_LSA_EXTERNAL; +		ospf_ia_router_route(ospf, rtrs, &p, new_or, abr_or); +	} + +	return 0;  } -static void -ospf_examine_summaries (struct ospf_area *area, -			struct route_table *lsdb_rt, -                        struct route_table *rt, -                        struct route_table *rtrs) +static void ospf_examine_summaries(struct ospf_area *area, +				   struct route_table *lsdb_rt, +				   struct route_table *rt, +				   struct route_table *rtrs)  { -  struct ospf_lsa *lsa; -  struct route_node *rn; +	struct ospf_lsa *lsa; +	struct route_node *rn; -  LSDB_LOOP (lsdb_rt, rn, lsa) -    process_summary_lsa (area, rt, rtrs, lsa); +	LSDB_LOOP(lsdb_rt, rn, lsa) +	process_summary_lsa(area, rt, rtrs, lsa);  } -int -ospf_area_is_transit (struct ospf_area *area) +int ospf_area_is_transit(struct ospf_area *area)  { -  return (area->transit == OSPF_TRANSIT_TRUE) || -    ospf_full_virtual_nbrs(area); /* Cisco forgets to set the V-bit :( */ +	return (area->transit == OSPF_TRANSIT_TRUE) +	       || ospf_full_virtual_nbrs( +			  area); /* Cisco forgets to set the V-bit :( */  } -static void -ospf_update_network_route (struct ospf *ospf, -			   struct route_table *rt,  -                           struct route_table *rtrs, -                           struct summary_lsa *lsa, -                           struct prefix_ipv4 *p, -                           struct ospf_area *area) +static void ospf_update_network_route(struct ospf *ospf, struct route_table *rt, +				      struct route_table *rtrs, +				      struct summary_lsa *lsa, +				      struct prefix_ipv4 *p, +				      struct ospf_area *area)  { -  struct route_node *rn; -  struct ospf_route *or, *abr_or, *new_or; -  struct prefix_ipv4 abr; -  u_int32_t cost; - -  abr.family = AF_INET; -  abr.prefix =lsa->header.adv_router; -  abr.prefixlen = IPV4_MAX_BITLEN; -  apply_mask_ipv4 (&abr); - -  abr_or = ospf_find_abr_route (rtrs, &abr, area); - -  if (abr_or == NULL) -    { -      if (IS_DEBUG_OSPF_EVENT) -	zlog_debug ("ospf_update_network_route(): can't find a route to the ABR"); -      return; -    } - -  cost = abr_or->cost + GET_METRIC (lsa->metric); - -  rn = route_node_lookup (rt, (struct prefix *) p); - -  if (! rn) -    { -      if (ospf->abr_type != OSPF_ABR_SHORTCUT) -        return; /* Standard ABR can update only already installed -                   backbone paths                                       */ -      if (IS_DEBUG_OSPF_EVENT) -	zlog_debug ("ospf_update_network_route(): " -		   "Allowing Shortcut ABR to add new route"); -      new_or = ospf_route_new (); -      new_or->type = OSPF_DESTINATION_NETWORK; -      new_or->id = lsa->header.id; -      new_or->mask = lsa->mask; -      new_or->u.std.options = lsa->header.options; -      new_or->u.std.origin = (struct lsa_header *) lsa; -      new_or->cost = cost; -      new_or->u.std.area_id = area->area_id; -      new_or->u.std.external_routing = area->external_routing; -      new_or->path_type = OSPF_PATH_INTER_AREA; -      ospf_route_add (rt, p, new_or, abr_or); - -      return; -    } -  else -    { -      route_unlock_node (rn); -      if (rn->info == NULL) -        return; -    } - -  or = rn->info; - -  if (or->path_type != OSPF_PATH_INTRA_AREA && -      or->path_type != OSPF_PATH_INTER_AREA) -    { -      if (IS_DEBUG_OSPF_EVENT) -	zlog_debug ("ospf_update_network_route(): ERR: path type is wrong"); -      return; -    } - -  if (ospf->abr_type == OSPF_ABR_SHORTCUT) -    { -      if (or->path_type == OSPF_PATH_INTRA_AREA && -	  !OSPF_IS_AREA_ID_BACKBONE (or->u.std.area_id)) -	{ -	  if (IS_DEBUG_OSPF_EVENT) -	    zlog_debug ("ospf_update_network_route(): Shortcut: " -		       "this intra-area path is not backbone"); -	  return; +	struct route_node *rn; +	struct ospf_route * or, *abr_or, *new_or; +	struct prefix_ipv4 abr; +	u_int32_t cost; + +	abr.family = AF_INET; +	abr.prefix = lsa->header.adv_router; +	abr.prefixlen = IPV4_MAX_BITLEN; +	apply_mask_ipv4(&abr); + +	abr_or = ospf_find_abr_route(rtrs, &abr, area); + +	if (abr_or == NULL) { +		if (IS_DEBUG_OSPF_EVENT) +			zlog_debug( +				"ospf_update_network_route(): can't find a route to the ABR"); +		return;  	} -    } -  else   /* Not Shortcut ABR */ -    { -      if (!OSPF_IS_AREA_ID_BACKBONE (or->u.std.area_id)) -	{ -	  if (IS_DEBUG_OSPF_EVENT) -	    zlog_debug ("ospf_update_network_route(): " -		       "route is not BB-associated"); -	  return; /* We can update only BB routes */ + +	cost = abr_or->cost + GET_METRIC(lsa->metric); + +	rn = route_node_lookup(rt, (struct prefix *)p); + +	if (!rn) { +		if (ospf->abr_type != OSPF_ABR_SHORTCUT) +			return; /* Standard ABR can update only already +				   installed +				   backbone paths */ +		if (IS_DEBUG_OSPF_EVENT) +			zlog_debug( +				"ospf_update_network_route(): " +				"Allowing Shortcut ABR to add new route"); +		new_or = ospf_route_new(); +		new_or->type = OSPF_DESTINATION_NETWORK; +		new_or->id = lsa->header.id; +		new_or->mask = lsa->mask; +		new_or->u.std.options = lsa->header.options; +		new_or->u.std.origin = (struct lsa_header *)lsa; +		new_or->cost = cost; +		new_or->u.std.area_id = area->area_id; +		new_or->u.std.external_routing = area->external_routing; +		new_or->path_type = OSPF_PATH_INTER_AREA; +		ospf_route_add(rt, p, new_or, abr_or); + +		return; +	} else { +		route_unlock_node(rn); +		if (rn->info == NULL) +			return;  	} -    } - -  if (or->cost < cost) -    { -      if (IS_DEBUG_OSPF_EVENT) -	zlog_debug ("ospf_update_network_route(): new route is worse"); -      return; -    } - -  if (or->cost == cost) -    { -      if (IS_DEBUG_OSPF_EVENT) -	zlog_debug ("ospf_update_network_route(): " -		   "new route is same distance, adding nexthops"); -      ospf_route_copy_nexthops (or, abr_or->paths); -    } - -  if (or->cost > cost) -    { -      if (IS_DEBUG_OSPF_EVENT) -	zlog_debug ("ospf_update_network_route(): " -		   "new route is better, overriding nexthops"); -      ospf_route_subst_nexthops (or, abr_or->paths); -      or->cost = cost; - -      if ((ospf->abr_type == OSPF_ABR_SHORTCUT) && -	  !OSPF_IS_AREA_ID_BACKBONE (or->u.std.area_id)) -	{ -	  or->path_type = OSPF_PATH_INTER_AREA; -	  or->u.std.area_id = area->area_id; -	  or->u.std.external_routing = area->external_routing; -          /* Note that we can do this only in Shortcut ABR mode, -             because standard ABR must leave the route type and area -             unchanged -          */ -        } -    } -} -static void -ospf_update_router_route (struct ospf *ospf, -			  struct route_table *rtrs,  -                          struct summary_lsa *lsa, -                          struct prefix_ipv4 *p, -                          struct ospf_area *area) -{ -  struct ospf_route *or, *abr_or, *new_or; -  struct prefix_ipv4 abr; -  u_int32_t cost; - -  abr.family = AF_INET; -  abr.prefix = lsa->header.adv_router; -  abr.prefixlen = IPV4_MAX_BITLEN; -  apply_mask_ipv4 (&abr); - -  abr_or = ospf_find_abr_route (rtrs, &abr, area); - -  if (abr_or == NULL) -    { -      if (IS_DEBUG_OSPF_EVENT) -	zlog_debug ("ospf_update_router_route(): can't find a route to the ABR"); -      return; -    } - -  cost = abr_or->cost + GET_METRIC (lsa->metric); - -  /* First try to find a backbone path, -     because standard ABR can update only BB-associated paths */ - -  if ((ospf->backbone == NULL) && -      (ospf->abr_type != OSPF_ABR_SHORTCUT)) -     return; /* no BB area, not Shortcut ABR, exiting */ -   -  /* find the backbone route, if possible */ -  if ((ospf->backbone == NULL) -      || !(or = ospf_find_asbr_route_through_area (rtrs, p, ospf->backbone))) -    { -      if (ospf->abr_type != OSPF_ABR_SHORTCUT) - -         /* route to ASBR through the BB not found -            the router is not Shortcut ABR, exiting */ - -          return; -      else -	/* We're a Shortcut ABR*/ +	or = rn->info; + +	if (or->path_type != OSPF_PATH_INTRA_AREA && +	    or->path_type != OSPF_PATH_INTER_AREA) { +		if (IS_DEBUG_OSPF_EVENT) +			zlog_debug( +				"ospf_update_network_route(): ERR: path type is wrong"); +		return; +	} + +	if (ospf->abr_type == OSPF_ABR_SHORTCUT) { +		if ( +			or->path_type == OSPF_PATH_INTRA_AREA +				  && !OSPF_IS_AREA_ID_BACKBONE( +					     or->u.std.area_id)) { +			if (IS_DEBUG_OSPF_EVENT) +				zlog_debug( +					"ospf_update_network_route(): Shortcut: " +					"this intra-area path is not backbone"); +			return; +		} +	} else /* Not Shortcut ABR */  	{ -	  /* Let it either add a new router or update the route -	     through the same (non-BB) area. */ - -	  new_or = ospf_route_new (); -	  new_or->type = OSPF_DESTINATION_ROUTER; -	  new_or->id = lsa->header.id; -	  new_or->mask = lsa->mask; -	  new_or->u.std.options = lsa->header.options; -	  new_or->u.std.origin = (struct lsa_header *)lsa; -	  new_or->cost = cost; -	  new_or->u.std.area_id = area->area_id; -	  new_or->u.std.external_routing = area->external_routing; -	  new_or->path_type = OSPF_PATH_INTER_AREA; -	  new_or->u.std.flags = ROUTER_LSA_EXTERNAL; -	  ospf_ia_router_route (ospf, rtrs, p, new_or, abr_or); - -          return; -        } -    } - -  /* At this point the "or" is always bb-associated */ - -  if (!(or->u.std.flags & ROUTER_LSA_EXTERNAL)) -    { -      if (IS_DEBUG_OSPF_EVENT) -	zlog_debug ("ospf_upd_router_route(): the remote router is not an ASBR"); -      return; -    } - -  if (or->path_type != OSPF_PATH_INTRA_AREA && -      or->path_type != OSPF_PATH_INTER_AREA) -    return; - -  if (or->cost < cost) -    return; - -  else if (or->cost == cost) -    ospf_route_copy_nexthops (or, abr_or->paths); - -  else if (or->cost > cost) -    { -      ospf_route_subst_nexthops (or, abr_or->paths); -      or->cost = cost; - -      /* Even if the ABR runs in Shortcut mode, we can't change -         the path type and area, because the "or" is always bb-associated -         at this point and even Shortcut ABR can't change these attributes */ -    } -} +		if (!OSPF_IS_AREA_ID_BACKBONE(or->u.std.area_id)) { +			if (IS_DEBUG_OSPF_EVENT) +				zlog_debug( +					"ospf_update_network_route(): " +					"route is not BB-associated"); +			return; /* We can update only BB routes */ +		} +	} -static int -process_transit_summary_lsa (struct ospf_area *area, struct route_table *rt, -			     struct route_table *rtrs, struct ospf_lsa *lsa) -{ -  struct ospf *ospf = area->ospf; -  struct summary_lsa *sl; -  struct prefix_ipv4 p; -  u_int32_t metric; - -  if (lsa == NULL) -    return 0; - -  sl = (struct summary_lsa *) lsa->data; - -  if (IS_DEBUG_OSPF_EVENT) -    zlog_debug ("process_transit_summaries(): LS ID: %s", -	       inet_ntoa (lsa->data->id)); -  metric = GET_METRIC (sl->metric); -    -  if (metric == OSPF_LS_INFINITY) -    { -      if (IS_DEBUG_OSPF_EVENT) -	zlog_debug ("process_transit_summaries(): metric is infinity, skip"); -      return 0; -    } - -  if (IS_LSA_MAXAGE (lsa)) -    { -      if (IS_DEBUG_OSPF_EVENT) -	zlog_debug ("process_transit_summaries(): This LSA is too old"); -      return 0; -    } - -  if (ospf_lsa_is_self_originated (area->ospf, lsa)) -    {  -      if (IS_DEBUG_OSPF_EVENT) -	zlog_debug ("process_transit_summaries(): This LSA is mine, skip"); -      return 0; -    } - -  p.family = AF_INET; -  p.prefix = sl->header.id; -    -  if (sl->header.type == OSPF_SUMMARY_LSA) -    p.prefixlen = ip_masklen (sl->mask); -  else -    p.prefixlen = IPV4_MAX_BITLEN; -       -  apply_mask_ipv4 (&p); - -  if (sl->header.type == OSPF_SUMMARY_LSA) -    ospf_update_network_route (ospf, rt, rtrs, sl, &p, area); -  else -    ospf_update_router_route (ospf, rtrs, sl, &p, area); -  -  return 0; -} +	if (or->cost < cost) { +		if (IS_DEBUG_OSPF_EVENT) +			zlog_debug( +				"ospf_update_network_route(): new route is worse"); +		return; +	} -static void -ospf_examine_transit_summaries (struct ospf_area *area, -				struct route_table *lsdb_rt, -                                struct route_table *rt, -                                struct route_table *rtrs) -{ -  struct ospf_lsa *lsa; -  struct route_node *rn; +	if (or->cost == cost) { +		if (IS_DEBUG_OSPF_EVENT) +			zlog_debug( +				"ospf_update_network_route(): " +				"new route is same distance, adding nexthops"); +		ospf_route_copy_nexthops(or, abr_or->paths); +	} -  LSDB_LOOP (lsdb_rt, rn, lsa) -    process_transit_summary_lsa (area, rt, rtrs, lsa); +	if (or->cost > cost) { +		if (IS_DEBUG_OSPF_EVENT) +			zlog_debug( +				"ospf_update_network_route(): " +				"new route is better, overriding nexthops"); +		ospf_route_subst_nexthops(or, abr_or->paths); +		or->cost = cost; + +		if ((ospf->abr_type == OSPF_ABR_SHORTCUT) +		    && !OSPF_IS_AREA_ID_BACKBONE(or->u.std.area_id)) { +			or->path_type = OSPF_PATH_INTER_AREA; +			or->u.std.area_id = area->area_id; +			or->u.std.external_routing = area->external_routing; +			/* Note that we can do this only in Shortcut ABR mode, +			   because standard ABR must leave the route type and +			   area +			   unchanged +			*/ +		} +	}  } -void -ospf_ia_routing (struct ospf *ospf, -		 struct route_table *rt, -                 struct route_table *rtrs) +static void ospf_update_router_route(struct ospf *ospf, +				     struct route_table *rtrs, +				     struct summary_lsa *lsa, +				     struct prefix_ipv4 *p, +				     struct ospf_area *area)  { -  struct ospf_area * area; +	struct ospf_route * or, *abr_or, *new_or; +	struct prefix_ipv4 abr; +	u_int32_t cost; + +	abr.family = AF_INET; +	abr.prefix = lsa->header.adv_router; +	abr.prefixlen = IPV4_MAX_BITLEN; +	apply_mask_ipv4(&abr); + +	abr_or = ospf_find_abr_route(rtrs, &abr, area); + +	if (abr_or == NULL) { +		if (IS_DEBUG_OSPF_EVENT) +			zlog_debug( +				"ospf_update_router_route(): can't find a route to the ABR"); +		return; +	} -  if (IS_DEBUG_OSPF_EVENT) -    zlog_debug ("ospf_ia_routing():start"); +	cost = abr_or->cost + GET_METRIC(lsa->metric); -  if (IS_OSPF_ABR (ospf)) -    { -      struct listnode *node;  -      struct ospf_area *area; +	/* First try to find a backbone path, +	   because standard ABR can update only BB-associated paths */ -      switch (ospf->abr_type) -        { -        case OSPF_ABR_STAND: -	  if (IS_DEBUG_OSPF_EVENT) -	    zlog_debug ("ospf_ia_routing():Standard ABR"); +	if ((ospf->backbone == NULL) && (ospf->abr_type != OSPF_ABR_SHORTCUT)) +		return; /* no BB area, not Shortcut ABR, exiting */ -          if ((area = ospf->backbone)) -            { -              struct listnode *node; +	/* find the backbone route, if possible */ +	if ((ospf->backbone == NULL) +	    || !(or = ospf_find_asbr_route_through_area(rtrs, p, +							ospf->backbone))) { +		if (ospf->abr_type != OSPF_ABR_SHORTCUT) -	      if (IS_DEBUG_OSPF_EVENT) -		{ -		  zlog_debug ("ospf_ia_routing():backbone area found"); -		  zlog_debug ("ospf_ia_routing():examining summaries"); -		} +			/* route to ASBR through the BB not found +			   the router is not Shortcut ABR, exiting */ -              OSPF_EXAMINE_SUMMARIES_ALL (area, rt, rtrs); - -	      for (ALL_LIST_ELEMENTS_RO (ospf->areas, node, area)) -                if (area != ospf->backbone) -                  if (ospf_area_is_transit (area)) -                    OSPF_EXAMINE_TRANSIT_SUMMARIES_ALL (area, rt, rtrs); -            } -          else -	    if (IS_DEBUG_OSPF_EVENT) -	      zlog_debug ("ospf_ia_routing():backbone area NOT found"); -          break; -        case OSPF_ABR_IBM: -        case OSPF_ABR_CISCO: -	  if (IS_DEBUG_OSPF_EVENT) -	    zlog_debug ("ospf_ia_routing():Alternative Cisco/IBM ABR"); -          area = ospf->backbone; /* Find the BB */ - -          /* If we have an active BB connection */ -          if (area && ospf_act_bb_connection (ospf)) -            { -	      if (IS_DEBUG_OSPF_EVENT) +			return; +		else +		/* We're a Shortcut ABR*/  		{ -		  zlog_debug ("ospf_ia_routing(): backbone area found"); -		  zlog_debug ("ospf_ia_routing(): examining BB summaries"); +			/* Let it either add a new router or update the route +			   through the same (non-BB) area. */ + +			new_or = ospf_route_new(); +			new_or->type = OSPF_DESTINATION_ROUTER; +			new_or->id = lsa->header.id; +			new_or->mask = lsa->mask; +			new_or->u.std.options = lsa->header.options; +			new_or->u.std.origin = (struct lsa_header *)lsa; +			new_or->cost = cost; +			new_or->u.std.area_id = area->area_id; +			new_or->u.std.external_routing = area->external_routing; +			new_or->path_type = OSPF_PATH_INTER_AREA; +			new_or->u.std.flags = ROUTER_LSA_EXTERNAL; +			ospf_ia_router_route(ospf, rtrs, p, new_or, abr_or); + +			return;  		} +	} -              OSPF_EXAMINE_SUMMARIES_ALL (area, rt, rtrs); - -	      for (ALL_LIST_ELEMENTS_RO (ospf->areas, node, area)) -                if (area != ospf->backbone) -                  if (ospf_area_is_transit (area)) -                    OSPF_EXAMINE_TRANSIT_SUMMARIES_ALL (area, rt, rtrs); -            } -          else -            { /* No active BB connection--consider all areas */ -	      if (IS_DEBUG_OSPF_EVENT) -		zlog_debug ("ospf_ia_routing(): " -			   "Active BB connection not found"); -	      for (ALL_LIST_ELEMENTS_RO (ospf->areas, node, area)) -                OSPF_EXAMINE_SUMMARIES_ALL (area, rt, rtrs); -            } -          break; -        case OSPF_ABR_SHORTCUT: -	  if (IS_DEBUG_OSPF_EVENT) -	    zlog_debug ("ospf_ia_routing():Alternative Shortcut"); -          area = ospf->backbone; /* Find the BB */ - -          /* If we have an active BB connection */ -          if (area && ospf_act_bb_connection (ospf)) -            { -	      if (IS_DEBUG_OSPF_EVENT) -		{ -		  zlog_debug ("ospf_ia_routing(): backbone area found"); -		  zlog_debug ("ospf_ia_routing(): examining BB summaries"); +	/* At this point the "or" is always bb-associated */ + +	if (!(or->u.std.flags & ROUTER_LSA_EXTERNAL)) { +		if (IS_DEBUG_OSPF_EVENT) +			zlog_debug( +				"ospf_upd_router_route(): the remote router is not an ASBR"); +		return; +	} + +	if (or->path_type != OSPF_PATH_INTRA_AREA && +	    or->path_type != OSPF_PATH_INTER_AREA) +		return; + +	if (or->cost < cost) +		return; + +	else if (or->cost == cost) +		ospf_route_copy_nexthops(or, abr_or->paths); + +	else if (or->cost > cost) { +		ospf_route_subst_nexthops(or, abr_or->paths); +		or->cost = cost; + +		/* Even if the ABR runs in Shortcut mode, we can't change +		   the path type and area, because the "or" is always +		   bb-associated +		   at this point and even Shortcut ABR can't change these +		   attributes */ +	} +} + +static int process_transit_summary_lsa(struct ospf_area *area, +				       struct route_table *rt, +				       struct route_table *rtrs, +				       struct ospf_lsa *lsa) +{ +	struct ospf *ospf = area->ospf; +	struct summary_lsa *sl; +	struct prefix_ipv4 p; +	u_int32_t metric; + +	if (lsa == NULL) +		return 0; + +	sl = (struct summary_lsa *)lsa->data; + +	if (IS_DEBUG_OSPF_EVENT) +		zlog_debug("process_transit_summaries(): LS ID: %s", +			   inet_ntoa(lsa->data->id)); +	metric = GET_METRIC(sl->metric); + +	if (metric == OSPF_LS_INFINITY) { +		if (IS_DEBUG_OSPF_EVENT) +			zlog_debug( +				"process_transit_summaries(): metric is infinity, skip"); +		return 0; +	} + +	if (IS_LSA_MAXAGE(lsa)) { +		if (IS_DEBUG_OSPF_EVENT) +			zlog_debug( +				"process_transit_summaries(): This LSA is too old"); +		return 0; +	} + +	if (ospf_lsa_is_self_originated(area->ospf, lsa)) { +		if (IS_DEBUG_OSPF_EVENT) +			zlog_debug( +				"process_transit_summaries(): This LSA is mine, skip"); +		return 0; +	} + +	p.family = AF_INET; +	p.prefix = sl->header.id; + +	if (sl->header.type == OSPF_SUMMARY_LSA) +		p.prefixlen = ip_masklen(sl->mask); +	else +		p.prefixlen = IPV4_MAX_BITLEN; + +	apply_mask_ipv4(&p); + +	if (sl->header.type == OSPF_SUMMARY_LSA) +		ospf_update_network_route(ospf, rt, rtrs, sl, &p, area); +	else +		ospf_update_router_route(ospf, rtrs, sl, &p, area); + +	return 0; +} + +static void ospf_examine_transit_summaries(struct ospf_area *area, +					   struct route_table *lsdb_rt, +					   struct route_table *rt, +					   struct route_table *rtrs) +{ +	struct ospf_lsa *lsa; +	struct route_node *rn; + +	LSDB_LOOP(lsdb_rt, rn, lsa) +	process_transit_summary_lsa(area, rt, rtrs, lsa); +} + +void ospf_ia_routing(struct ospf *ospf, struct route_table *rt, +		     struct route_table *rtrs) +{ +	struct ospf_area *area; + +	if (IS_DEBUG_OSPF_EVENT) +		zlog_debug("ospf_ia_routing():start"); + +	if (IS_OSPF_ABR(ospf)) { +		struct listnode *node; +		struct ospf_area *area; + +		switch (ospf->abr_type) { +		case OSPF_ABR_STAND: +			if (IS_DEBUG_OSPF_EVENT) +				zlog_debug("ospf_ia_routing():Standard ABR"); + +			if ((area = ospf->backbone)) { +				struct listnode *node; + +				if (IS_DEBUG_OSPF_EVENT) { +					zlog_debug( +						"ospf_ia_routing():backbone area found"); +					zlog_debug( +						"ospf_ia_routing():examining summaries"); +				} + +				OSPF_EXAMINE_SUMMARIES_ALL(area, rt, rtrs); + +				for (ALL_LIST_ELEMENTS_RO(ospf->areas, node, +							  area)) +					if (area != ospf->backbone) +						if (ospf_area_is_transit(area)) +							OSPF_EXAMINE_TRANSIT_SUMMARIES_ALL( +								area, rt, rtrs); +			} else if (IS_DEBUG_OSPF_EVENT) +				zlog_debug( +					"ospf_ia_routing():backbone area NOT found"); +			break; +		case OSPF_ABR_IBM: +		case OSPF_ABR_CISCO: +			if (IS_DEBUG_OSPF_EVENT) +				zlog_debug( +					"ospf_ia_routing():Alternative Cisco/IBM ABR"); +			area = ospf->backbone; /* Find the BB */ + +			/* If we have an active BB connection */ +			if (area && ospf_act_bb_connection(ospf)) { +				if (IS_DEBUG_OSPF_EVENT) { +					zlog_debug( +						"ospf_ia_routing(): backbone area found"); +					zlog_debug( +						"ospf_ia_routing(): examining BB summaries"); +				} + +				OSPF_EXAMINE_SUMMARIES_ALL(area, rt, rtrs); + +				for (ALL_LIST_ELEMENTS_RO(ospf->areas, node, +							  area)) +					if (area != ospf->backbone) +						if (ospf_area_is_transit(area)) +							OSPF_EXAMINE_TRANSIT_SUMMARIES_ALL( +								area, rt, rtrs); +			} else { /* No active BB connection--consider all areas +				    */ +				if (IS_DEBUG_OSPF_EVENT) +					zlog_debug( +						"ospf_ia_routing(): " +						"Active BB connection not found"); +				for (ALL_LIST_ELEMENTS_RO(ospf->areas, node, +							  area)) +					OSPF_EXAMINE_SUMMARIES_ALL(area, rt, +								   rtrs); +			} +			break; +		case OSPF_ABR_SHORTCUT: +			if (IS_DEBUG_OSPF_EVENT) +				zlog_debug( +					"ospf_ia_routing():Alternative Shortcut"); +			area = ospf->backbone; /* Find the BB */ + +			/* If we have an active BB connection */ +			if (area && ospf_act_bb_connection(ospf)) { +				if (IS_DEBUG_OSPF_EVENT) { +					zlog_debug( +						"ospf_ia_routing(): backbone area found"); +					zlog_debug( +						"ospf_ia_routing(): examining BB summaries"); +				} +				OSPF_EXAMINE_SUMMARIES_ALL(area, rt, rtrs); +			} + +			for (ALL_LIST_ELEMENTS_RO(ospf->areas, node, area)) +				if (area != ospf->backbone) +					if (ospf_area_is_transit(area) +					    || ((area->shortcut_configured +						 != OSPF_SHORTCUT_DISABLE) +						&& ((ospf->backbone == NULL) +						    || ((area->shortcut_configured +							 == OSPF_SHORTCUT_ENABLE) +							&& area->shortcut_capability)))) +						OSPF_EXAMINE_TRANSIT_SUMMARIES_ALL( +							area, rt, rtrs); +			break; +		default: +			break;  		} -              OSPF_EXAMINE_SUMMARIES_ALL (area, rt, rtrs); -            } - -	  for (ALL_LIST_ELEMENTS_RO (ospf->areas, node, area)) -            if (area != ospf->backbone) -              if (ospf_area_is_transit (area) || -                  ((area->shortcut_configured != OSPF_SHORTCUT_DISABLE) && -                  ((ospf->backbone == NULL) || -                  ((area->shortcut_configured == OSPF_SHORTCUT_ENABLE) && -                  area->shortcut_capability)))) -                OSPF_EXAMINE_TRANSIT_SUMMARIES_ALL (area, rt, rtrs); -          break; -        default: -          break; -        } -    } -  else  -    { -      struct listnode *node; - -      if (IS_DEBUG_OSPF_EVENT) -	zlog_debug ("ospf_ia_routing():not ABR, considering all areas"); - -      for (ALL_LIST_ELEMENTS_RO (ospf->areas, node, area)) -        OSPF_EXAMINE_SUMMARIES_ALL (area, rt, rtrs); -    } +	} else { +		struct listnode *node; + +		if (IS_DEBUG_OSPF_EVENT) +			zlog_debug( +				"ospf_ia_routing():not ABR, considering all areas"); + +		for (ALL_LIST_ELEMENTS_RO(ospf->areas, node, area)) +			OSPF_EXAMINE_SUMMARIES_ALL(area, rt, rtrs); +	}  }  | 
