summaryrefslogtreecommitdiff
path: root/ospf6d/ospf6_abr.c
diff options
context:
space:
mode:
Diffstat (limited to 'ospf6d/ospf6_abr.c')
-rw-r--r--ospf6d/ospf6_abr.c380
1 files changed, 299 insertions, 81 deletions
diff --git a/ospf6d/ospf6_abr.c b/ospf6d/ospf6_abr.c
index 04a55c46..397cef76 100644
--- a/ospf6d/ospf6_abr.c
+++ b/ospf6d/ospf6_abr.c
@@ -34,18 +34,42 @@
#include "ospf6_lsa.h"
#include "ospf6_route.h"
#include "ospf6_lsdb.h"
+#include "ospf6_message.h"
+
#include "ospf6_top.h"
#include "ospf6_area.h"
#include "ospf6_interface.h"
+#include "ospf6_neighbor.h"
+
#include "ospf6_abr.h"
+#include "ospf6_flood.h"
#include "ospf6d.h"
unsigned char conf_debug_ospf6_abr;
+int
+ospf6_is_router_abr (struct ospf6 *o)
+{
+ listnode node;
+ struct ospf6_area *oa;
+ int area_count = 0;
+
+ for (node = listhead (o->area_list); node; nextnode (node))
+ {
+ oa = OSPF6_AREA (getdata (node));
+ if (IS_AREA_ENABLED (oa))
+ area_count++;
+ }
+
+ if (area_count > 1)
+ return 1;
+ return 0;
+}
+
/* RFC 2328 12.4.3. Summary-LSAs */
void
-ospf6_abr_originate_prefix_to_area (struct ospf6_route *route,
- struct ospf6_area *area)
+ospf6_abr_originate_summary_to_area (struct ospf6_route *route,
+ struct ospf6_area *area)
{
struct ospf6_lsa *lsa, *old = NULL;
struct ospf6_interface *oi;
@@ -55,26 +79,63 @@ ospf6_abr_originate_prefix_to_area (struct ospf6_route *route,
struct ospf6_lsa_header *lsa_header;
caddr_t p;
struct ospf6_inter_prefix_lsa *prefix_lsa;
+ struct ospf6_inter_router_lsa *router_lsa;
+ struct ospf6_route_table *summary_table = NULL;
+ u_int16_t type;
+
+ if (IS_OSPF6_DEBUG_ABR)
+ {
+ char buf[64];
+ if (route->type == OSPF6_DEST_TYPE_ROUTER)
+ {
+ inet_ntop (AF_INET,
+ &(ospf6_linkstate_prefix_adv_router (&route->prefix)),
+ buf, sizeof (buf));
+ zlog_info ("Originating summary in area %s for ASBR %s",
+ area->name, buf);
+ }
+ else
+ {
+ prefix2str (&route->prefix, buf, sizeof (buf));
+ zlog_info ("Originating summary in area %s for %s",
+ area->name, buf);
+ }
+ }
- summary = ospf6_route_lookup (&route->prefix, area->summary_table);
+ if (route->type == OSPF6_DEST_TYPE_ROUTER)
+ summary_table = area->summary_router;
+ else
+ summary_table = area->summary_prefix;
+ summary = ospf6_route_lookup (&route->prefix, summary_table);
if (summary)
- old = ospf6_lsdb_lookup (htons (OSPF6_LSTYPE_INTER_PREFIX),
+ old = ospf6_lsdb_lookup (summary->path.origin.type,
summary->path.origin.id,
area->ospf6->router_id, area->lsdb);
/* if this route has just removed, remove corresponding LSA */
if (CHECK_FLAG (route->flag, OSPF6_ROUTE_REMOVE))
{
+ if (IS_OSPF6_DEBUG_ABR)
+ zlog_info ("The route has just removed, purge previous LSA");
+ if (summary)
+ ospf6_route_remove (summary, summary_table);
if (old)
- ospf6_lsa_premature_aging (old);
+ ospf6_lsa_purge (old);
return;
}
- /* Only destination type network and address range are considered */
- if (route->type != OSPF6_DEST_TYPE_NETWORK)
+ /* Only destination type network, range or ASBR are considered */
+ if (route->type != OSPF6_DEST_TYPE_NETWORK &&
+ route->type != OSPF6_DEST_TYPE_RANGE &&
+ (route->type != OSPF6_DEST_TYPE_ROUTER ||
+ ! CHECK_FLAG (route->path.router_bits, OSPF6_ROUTER_BIT_E)))
{
+ if (IS_OSPF6_DEBUG_ABR)
+ zlog_info ("Route type is none of network, range nor ASBR, withdraw");
+ if (summary)
+ ospf6_route_remove (summary, summary_table);
if (old)
- ospf6_lsa_premature_aging (old);
+ ospf6_lsa_purge (old);
return;
}
@@ -82,95 +143,203 @@ ospf6_abr_originate_prefix_to_area (struct ospf6_route *route,
if (route->path.type == OSPF6_PATH_TYPE_EXTERNAL1 ||
route->path.type == OSPF6_PATH_TYPE_EXTERNAL2)
{
+ if (IS_OSPF6_DEBUG_ABR)
+ zlog_info ("Path type is external, withdraw");
+ if (summary)
+ ospf6_route_remove (summary, summary_table);
if (old)
- ospf6_lsa_premature_aging (old);
+ ospf6_lsa_purge (old);
return;
}
- /* do not generate if the route cost is greater or equal to LSInfinity */
- if (route->path.cost >= LS_INFINITY)
+ /* do not generate if the path's area is the same as target area */
+ if (route->path.area_id == area->area_id)
{
+ if (IS_OSPF6_DEBUG_ABR)
+ zlog_info ("The route is in the area itself, ignore");
+ if (summary)
+ ospf6_route_remove (summary, summary_table);
if (old)
- ospf6_lsa_premature_aging (old);
+ ospf6_lsa_purge (old);
return;
}
- /* if this is an inter-area route */
- if (route->path.type == OSPF6_PATH_TYPE_INTRA)
+ /* do not generate if the nexthops belongs to the target area */
+ oi = ospf6_interface_lookup_by_ifindex (route->nexthop[0].ifindex);
+ if (oi && oi->area && oi->area == area)
{
- /* search for configured address range for the route's area */
- route_area = ospf6_area_lookup (route->path.area_id, area->ospf6);
- assert (route_area);
- range = ospf6_route_lookup_bestmatch (&route->prefix,
- route_area->summary_table);
+ if (IS_OSPF6_DEBUG_ABR)
+ zlog_info ("The route's nexthop is in the same area, ignore");
+ if (summary)
+ ospf6_route_remove (summary, summary_table);
+ if (old)
+ ospf6_lsa_purge (old);
+ return;
}
- /* ranges are ignored when originate backbone routes to transit area.
- Otherwise, if ranges are configured, the route is suppressed. */
- if (range && (route->path.area_id != htonl (0) || ! area->transit_capability))
+ /* do not generate if the route cost is greater or equal to LSInfinity */
+ if (route->path.cost >= LS_INFINITY)
{
+ if (IS_OSPF6_DEBUG_ABR)
+ zlog_info ("The cost exceeds LSInfinity, withdraw");
+ if (summary)
+ ospf6_route_remove (summary, summary_table);
if (old)
- ospf6_lsa_premature_aging (old);
- if (range->path.cost < route->path.cost)
- range->path.cost = route->path.cost;
- SET_FLAG (range->flag, OSPF6_ROUTE_HAVE_LONGER);
+ ospf6_lsa_purge (old);
return;
}
- /* do not generate if the path's area is the same as target area */
- if (route->path.area_id == area->area_id)
+ /* if this is a route to ASBR */
+ if (route->type == OSPF6_DEST_TYPE_ROUTER)
{
- if (old)
- ospf6_lsa_premature_aging (old);
- return;
+ /* Only the prefered best path is considered */
+ if (! CHECK_FLAG (route->flag, OSPF6_ROUTE_BEST))
+ {
+ if (IS_OSPF6_DEBUG_ABR)
+ zlog_info ("This is the secondary path to the ASBR, ignore");
+ if (summary)
+ ospf6_route_remove (summary, summary_table);
+ if (old)
+ ospf6_lsa_purge (old);
+ return;
+ }
+
+ /* Do not generate if the area is stub */
+ /* XXX */
}
- /* do not generate if the nexthops belongs to the target area */
- oi = ospf6_interface_lookup_by_ifindex (route->nexthop[0].ifindex);
- if (oi && oi->area && oi->area->area_id == area->area_id)
+ /* if this is an intra-area route, this may be suppressed by aggregation */
+ if (route->type == OSPF6_DEST_TYPE_NETWORK &&
+ route->path.type == OSPF6_PATH_TYPE_INTRA)
{
- if (old)
- ospf6_lsa_premature_aging (old);
- return;
+ /* search for configured address range for the route's area */
+ route_area = ospf6_area_lookup (route->path.area_id, area->ospf6);
+ assert (route_area);
+ range = ospf6_route_lookup_bestmatch (&route->prefix,
+ route_area->range_table);
+
+ /* ranges are ignored when originate backbone routes to transit area.
+ Otherwise, if ranges are configured, the route is suppressed. */
+ if (range && ! CHECK_FLAG (range->flag, OSPF6_ROUTE_REMOVE) &&
+ (route->path.area_id != BACKBONE_AREA_ID ||
+ ! IS_AREA_TRANSIT (area)))
+ {
+ if (IS_OSPF6_DEBUG_ABR)
+ {
+ char buf[64];
+ prefix2str (&range->prefix, buf, sizeof (buf));
+ zlog_info ("Suppressed by range %s of area %s",
+ buf, route_area->name);
+ }
+
+ if (summary)
+ ospf6_route_remove (summary, summary_table);
+ if (old)
+ ospf6_lsa_purge (old);
+ return;
+ }
+ }
+
+ /* If this is a configured address range */
+ if (route->type == OSPF6_DEST_TYPE_RANGE)
+ {
+ /* If DoNotAdvertise is set */
+ if (CHECK_FLAG (route->flag, OSPF6_ROUTE_DO_NOT_ADVERTISE))
+ {
+ if (IS_OSPF6_DEBUG_ABR)
+ zlog_info ("This is the range with DoNotAdvertise set. ignore");
+ if (summary)
+ ospf6_route_remove (summary, summary_table);
+ if (old)
+ ospf6_lsa_purge (old);
+ return;
+ }
+
+ /* Whether the route have active longer prefix */
+ if (! CHECK_FLAG (route->flag, OSPF6_ROUTE_ACTIVE_SUMMARY))
+ {
+ if (IS_OSPF6_DEBUG_ABR)
+ zlog_info ("The range is not active. withdraw");
+ if (summary)
+ ospf6_route_remove (summary, summary_table);
+ if (old)
+ ospf6_lsa_purge (old);
+ return;
+ }
}
/* the route is going to be originated. store it in area's summary_table */
if (summary == NULL)
{
summary = ospf6_route_copy (route);
- summary->path.origin.type = htons (OSPF6_LSTYPE_INTER_PREFIX);
+ if (route->type == OSPF6_DEST_TYPE_NETWORK ||
+ route->type == OSPF6_DEST_TYPE_RANGE)
+ summary->path.origin.type = htons (OSPF6_LSTYPE_INTER_PREFIX);
+ else
+ summary->path.origin.type = htons (OSPF6_LSTYPE_INTER_ROUTER);
summary->path.origin.adv_router = area->ospf6->router_id;
summary->path.origin.id =
ospf6_new_ls_id (summary->path.origin.type,
summary->path.origin.adv_router, area->lsdb);
- ospf6_route_add (summary, area->summary_table);
+ ospf6_route_add (summary, summary_table);
+ }
+ else
+ {
+ summary->type = route->type;
+ gettimeofday (&summary->changed, NULL);
}
+ summary->path.router_bits = route->path.router_bits;
+ summary->path.options[0] = route->path.options[0];
+ summary->path.options[1] = route->path.options[1];
+ summary->path.options[2] = route->path.options[2];
+ summary->path.prefix_options = route->path.prefix_options;
+ summary->path.area_id = area->area_id;
+ summary->path.type = OSPF6_PATH_TYPE_INTER;
+ summary->path.cost = route->path.cost;
+ summary->nexthop[0] = route->nexthop[0];
+
/* prepare buffer */
memset (buffer, 0, sizeof (buffer));
lsa_header = (struct ospf6_lsa_header *) buffer;
- prefix_lsa = (struct ospf6_inter_prefix_lsa *)
- ((caddr_t) lsa_header + sizeof (struct ospf6_lsa_header));
- p = (caddr_t) prefix_lsa + sizeof (struct ospf6_inter_prefix_lsa);
- /* Fill Inter-Area-Prefix-LSA */
- OSPF6_ABR_SUMMARY_METRIC_SET (prefix_lsa, route->path.cost);
-
- /* prefixlen */
- prefix_lsa->prefix.prefix_length = route->prefix.prefixlen;
-
- /* PrefixOptions */
- prefix_lsa->prefix.prefix_options = route->path.prefix_options;
-
- /* set Prefix */
- memcpy (p, &route->prefix.u.prefix6,
- OSPF6_PREFIX_SPACE (route->prefix.prefixlen));
- ospf6_prefix_apply_mask (&prefix_lsa->prefix);
- p += OSPF6_PREFIX_SPACE (route->prefix.prefixlen);
+ if (route->type == OSPF6_DEST_TYPE_ROUTER)
+ {
+ router_lsa = (struct ospf6_inter_router_lsa *)
+ ((caddr_t) lsa_header + sizeof (struct ospf6_lsa_header));
+ p = (caddr_t) router_lsa + sizeof (struct ospf6_inter_router_lsa);
+
+ /* Fill Inter-Area-Router-LSA */
+ router_lsa->options[0] = route->path.options[0];
+ router_lsa->options[1] = route->path.options[1];
+ router_lsa->options[2] = route->path.options[2];
+ OSPF6_ABR_SUMMARY_METRIC_SET (router_lsa, route->path.cost);
+ router_lsa->router_id =
+ ospf6_linkstate_prefix_adv_router (&route->prefix);
+ type = htons (OSPF6_LSTYPE_INTER_ROUTER);
+ }
+ else
+ {
+ prefix_lsa = (struct ospf6_inter_prefix_lsa *)
+ ((caddr_t) lsa_header + sizeof (struct ospf6_lsa_header));
+ p = (caddr_t) prefix_lsa + sizeof (struct ospf6_inter_prefix_lsa);
+
+ /* Fill Inter-Area-Prefix-LSA */
+ OSPF6_ABR_SUMMARY_METRIC_SET (prefix_lsa, route->path.cost);
+ prefix_lsa->prefix.prefix_length = route->prefix.prefixlen;
+ prefix_lsa->prefix.prefix_options = route->path.prefix_options;
+
+ /* set Prefix */
+ memcpy (p, &route->prefix.u.prefix6,
+ OSPF6_PREFIX_SPACE (route->prefix.prefixlen));
+ ospf6_prefix_apply_mask (&prefix_lsa->prefix);
+ p += OSPF6_PREFIX_SPACE (route->prefix.prefixlen);
+ type = htons (OSPF6_LSTYPE_INTER_PREFIX);
+ }
/* Fill LSA Header */
lsa_header->age = 0;
- lsa_header->type = htons (OSPF6_LSTYPE_INTER_PREFIX);
+ lsa_header->type = type;
lsa_header->id = summary->path.origin.id;
lsa_header->adv_router = area->ospf6->router_id;
lsa_header->seqnum =
@@ -183,23 +352,63 @@ ospf6_abr_originate_prefix_to_area (struct ospf6_route *route,
/* create LSA */
lsa = ospf6_lsa_create (lsa_header);
- lsa->scope = area;
- SET_FLAG (lsa->flag, OSPF6_LSA_REFRESH); /* XXX */
+
+ if (IS_OSPF6_DEBUG_ABR)
+ zlog_info ("Originate as %s", lsa->name);
/* Originate */
- ospf6_lsa_originate (lsa);
+ ospf6_lsa_originate_area (lsa, area);
+}
+
+void
+ospf6_abr_range_update (struct ospf6_route *range)
+{
+ u_int32_t cost = 0;
+ struct ospf6_route *ro;
+
+ assert (range->type == OSPF6_DEST_TYPE_RANGE);
+
+ /* update range's cost and active flag */
+ for (ro = ospf6_route_match_head (&range->prefix, ospf6->route_table);
+ ro; ro = ospf6_route_match_next (&range->prefix, ro))
+ {
+ if (ro->path.area_id == range->path.area_id &&
+ ! CHECK_FLAG (ro->flag, OSPF6_ROUTE_REMOVE))
+ cost = MAX (cost, ro->path.cost);
+ }
+
+ if (range->path.cost != cost)
+ {
+ range->path.cost = cost;
+
+ if (range->path.cost)
+ SET_FLAG (range->flag, OSPF6_ROUTE_ACTIVE_SUMMARY);
+ else
+ UNSET_FLAG (range->flag, OSPF6_ROUTE_ACTIVE_SUMMARY);
+
+ ospf6_abr_originate_summary (range);
+ }
}
void
-ospf6_abr_originate_prefix (struct ospf6_route *route, struct ospf6 *o)
+ospf6_abr_originate_summary (struct ospf6_route *route)
{
listnode node;
struct ospf6_area *oa;
+ struct ospf6_route *range = NULL;
- for (node = listhead (o->area_list); node; nextnode (node))
+ if (route->type == OSPF6_DEST_TYPE_NETWORK)
+ {
+ oa = ospf6_area_lookup (route->path.area_id, ospf6);
+ range = ospf6_route_lookup_bestmatch (&route->prefix, oa->range_table);
+ if (range)
+ ospf6_abr_range_update (range);
+ }
+
+ for (node = listhead (ospf6->area_list); node; nextnode (node))
{
oa = (struct ospf6_area *) getdata (node);
- ospf6_abr_originate_prefix_to_area (route, oa);
+ ospf6_abr_originate_summary_to_area (route, oa);
}
}
@@ -211,7 +420,7 @@ ospf6_abr_examin_summary (struct ospf6_lsa *lsa, struct ospf6_area *oa)
struct ospf6_route_table *table = NULL;
struct ospf6_route *range, *route, *old = NULL;
struct ospf6_route *abr_entry;
- u_char type;
+ u_char type = 0;
char options[3] = {0, 0, 0};
u_int8_t prefix_options = 0;
u_int32_t cost = 0;
@@ -274,18 +483,22 @@ ospf6_abr_examin_summary (struct ospf6_lsa *lsa, struct ospf6_area *oa)
}
/* (3) if the prefix is equal to an active configured address range */
- range = ospf6_route_lookup (&prefix, oa->summary_table);
- if (range && CHECK_FLAG (range->flag, OSPF6_ROUTE_HAVE_LONGER))
+ if (lsa->header->type == htons (OSPF6_LSTYPE_INTER_PREFIX))
{
- if (old)
- ospf6_route_remove (old, oa->ospf6->route_table);
- return;
+ range = ospf6_route_lookup (&prefix, oa->range_table);
+ if (range)
+ {
+ if (old)
+ ospf6_route_remove (old, oa->ospf6->route_table);
+ return;
+ }
}
/* (4) if the routing table entry for the ABR does not exist */
ospf6_linkstate_prefix (lsa->header->adv_router, htonl (0), &abr_prefix);
abr_entry = ospf6_route_lookup (&abr_prefix, oa->ospf6->brouter_table);
- if (abr_entry == NULL)
+ if (abr_entry == NULL || abr_entry->path.area_id != oa->area_id ||
+ ! CHECK_FLAG (abr_entry->path.router_bits, OSPF6_ROUTER_BIT_B))
{
if (old)
ospf6_route_remove (old, oa->ospf6->route_table);
@@ -318,11 +531,6 @@ ospf6_abr_examin_summary (struct ospf6_lsa *lsa, struct ospf6_area *oa)
ospf6_route_add (route, table);
}
-int
-dummy (struct ospf6_lsa *lsa)
-{
-}
-
/* Display functions */
int
@@ -412,15 +620,25 @@ install_element_ospf6_debug_abr ()
install_element (CONFIG_NODE, &no_debug_ospf6_abr_cmd);
}
+struct ospf6_lsa_handler inter_prefix_handler =
+{
+ OSPF6_LSTYPE_INTER_PREFIX,
+ "Inter-Prefix",
+ ospf6_inter_area_prefix_lsa_show
+};
+
+struct ospf6_lsa_handler inter_router_handler =
+{
+ OSPF6_LSTYPE_INTER_ROUTER,
+ "Inter-Router",
+ ospf6_inter_area_router_lsa_show
+};
+
void
ospf6_abr_init ()
{
- ospf6_lstype[3].name = "Inter-Area-Prefix-LSA";
- ospf6_lstype[3].reoriginate = dummy;
- ospf6_lstype[3].show = ospf6_inter_area_prefix_lsa_show;
- ospf6_lstype[4].name = "Inter-Area-Router-LSA";
- ospf6_lstype[4].reoriginate = dummy;
- ospf6_lstype[4].show = ospf6_inter_area_router_lsa_show;
+ ospf6_install_lsa_handler (&inter_prefix_handler);
+ ospf6_install_lsa_handler (&inter_router_handler);
}