summaryrefslogtreecommitdiffstats
path: root/ospf6d
diff options
context:
space:
mode:
Diffstat (limited to 'ospf6d')
-rw-r--r--ospf6d/ospf6_abr.c553
-rw-r--r--ospf6d/ospf6_abr.h7
-rw-r--r--ospf6d/ospf6_area.c323
-rw-r--r--ospf6d/ospf6_area.h7
-rw-r--r--ospf6d/ospf6_asbr.c92
-rw-r--r--ospf6d/ospf6_asbr.h1
-rw-r--r--ospf6d/ospf6_flood.c5
-rw-r--r--ospf6d/ospf6_flood.h2
-rw-r--r--ospf6d/ospf6_interface.c78
-rw-r--r--ospf6d/ospf6_interface.h8
-rw-r--r--ospf6d/ospf6_intra.c142
-rw-r--r--ospf6d/ospf6_lsa.h1
-rw-r--r--ospf6d/ospf6_lsdb.c35
-rw-r--r--ospf6d/ospf6_lsdb.h4
-rw-r--r--ospf6d/ospf6_main.c4
-rw-r--r--ospf6d/ospf6_message.c14
-rw-r--r--ospf6d/ospf6_network.c10
-rw-r--r--ospf6d/ospf6_network.h2
-rw-r--r--ospf6d/ospf6_route.c291
-rw-r--r--ospf6d/ospf6_route.h56
-rw-r--r--ospf6d/ospf6_spf.c154
-rw-r--r--ospf6d/ospf6_spf.h6
-rw-r--r--ospf6d/ospf6_top.c10
-rw-r--r--ospf6d/ospf6_zebra.c109
-rw-r--r--ospf6d/ospf6_zebra.h2
-rw-r--r--ospf6d/ospf6d.c8
26 files changed, 1506 insertions, 418 deletions
diff --git a/ospf6d/ospf6_abr.c b/ospf6d/ospf6_abr.c
index bb79900e..33299f48 100644
--- a/ospf6d/ospf6_abr.c
+++ b/ospf6d/ospf6_abr.c
@@ -38,6 +38,7 @@
#include "ospf6_route.h"
#include "ospf6_lsdb.h"
#include "ospf6_message.h"
+#include "ospf6_zebra.h"
#include "ospf6_top.h"
#include "ospf6_area.h"
@@ -67,53 +68,56 @@ ospf6_is_router_abr (struct ospf6 *o)
return 0;
}
+static int
+ospf6_abr_nexthops_belong_to_area (struct ospf6_route *route,
+ struct ospf6_area *area)
+{
+ struct ospf6_interface *oi;
+
+ oi = ospf6_interface_lookup_by_ifindex (ospf6_route_get_first_nh_index(route));
+ if (oi && oi->area && oi->area == area)
+ return 1;
+ else
+ return 0;
+}
+
+static void
+ospf6_abr_delete_route (struct ospf6_route *range, struct ospf6_route *summary,
+ struct ospf6_route_table *summary_table,
+ struct ospf6_lsa *old)
+{
+ if (summary)
+ {
+ ospf6_route_remove (summary, summary_table);
+ }
+
+ if (old && !OSPF6_LSA_IS_MAXAGE (old))
+ ospf6_lsa_purge (old);
+}
+
void
ospf6_abr_enable_area (struct ospf6_area *area)
{
struct ospf6_area *oa;
- struct ospf6_route *ro;
struct listnode *node, *nnode;
for (ALL_LIST_ELEMENTS (area->ospf6->area_list, node, nnode, oa))
- {
- /* update B bit for each area */
- OSPF6_ROUTER_LSA_SCHEDULE (oa);
-
- /* install other area's configured address range */
- if (oa != area)
- {
- for (ro = ospf6_route_head (oa->range_table); ro;
- ro = ospf6_route_next (ro))
- {
- if (CHECK_FLAG (ro->flag, OSPF6_ROUTE_ACTIVE_SUMMARY))
- ospf6_abr_originate_summary_to_area (ro, area);
- }
- }
- }
-
- /* install calculated routes to border routers */
- for (ro = ospf6_route_head (area->ospf6->brouter_table); ro;
- ro = ospf6_route_next (ro))
- ospf6_abr_originate_summary_to_area (ro, area);
-
- /* install calculated routes to network (may be rejected by ranges) */
- for (ro = ospf6_route_head (area->ospf6->route_table); ro;
- ro = ospf6_route_next (ro))
- ospf6_abr_originate_summary_to_area (ro, area);
+ /* update B bit for each area */
+ OSPF6_ROUTER_LSA_SCHEDULE (oa);
}
void
ospf6_abr_disable_area (struct ospf6_area *area)
{
struct ospf6_area *oa;
- struct ospf6_route *ro;
+ struct ospf6_route *ro, *nro;
struct ospf6_lsa *old;
struct listnode *node, *nnode;
/* Withdraw all summary prefixes previously originated */
- for (ro = ospf6_route_head (area->summary_prefix); ro;
- ro = ospf6_route_next (ro))
+ for (ro = ospf6_route_head (area->summary_prefix); ro; ro = nro)
{
+ nro = ospf6_route_next (ro);
old = ospf6_lsdb_lookup (ro->path.origin.type, ro->path.origin.id,
area->ospf6->router_id, area->lsdb);
if (old)
@@ -122,9 +126,9 @@ ospf6_abr_disable_area (struct ospf6_area *area)
}
/* Withdraw all summary router-routes previously originated */
- for (ro = ospf6_route_head (area->summary_router); ro;
- ro = ospf6_route_next (ro))
+ for (ro = ospf6_route_head (area->summary_router); ro; ro = nro)
{
+ nro = ospf6_route_next (ro);
old = ospf6_lsdb_lookup (ro->path.origin.type, ro->path.origin.id,
area->ospf6->router_id, area->lsdb);
if (old)
@@ -139,12 +143,13 @@ ospf6_abr_disable_area (struct ospf6_area *area)
}
/* RFC 2328 12.4.3. Summary-LSAs */
-void
+/* Returns 1 if a summary LSA has been generated for the area */
+/* This is used by the area/range logic to add/remove blackhole routes */
+int
ospf6_abr_originate_summary_to_area (struct ospf6_route *route,
struct ospf6_area *area)
{
struct ospf6_lsa *lsa, *old = NULL;
- struct ospf6_interface *oi;
struct ospf6_route *summary, *range = NULL;
struct ospf6_area *route_area;
char buffer[OSPF6_MAX_LSASIZE];
@@ -157,6 +162,54 @@ ospf6_abr_originate_summary_to_area (struct ospf6_route *route,
char buf[64];
int is_debug = 0;
+ /* 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_debug)
+ zlog_debug ("Route type is none of network, range nor ASBR, ignore");
+ return 0;
+ }
+
+ /* AS External routes are never considered */
+ if (route->path.type == OSPF6_PATH_TYPE_EXTERNAL1 ||
+ route->path.type == OSPF6_PATH_TYPE_EXTERNAL2)
+ {
+ if (is_debug)
+ zlog_debug ("Path type is external, skip");
+ return 0;
+ }
+
+ /* do not generate if the path's area is the same as target area */
+ if (route->path.area_id == area->area_id)
+ {
+ if (is_debug)
+ zlog_debug ("The route is in the area itself, ignore");
+ return 0;
+ }
+
+ /* do not generate if the nexthops belongs to the target area */
+ if (ospf6_abr_nexthops_belong_to_area (route, area))
+ {
+ if (is_debug)
+ zlog_debug ("The route's nexthop is in the same area, ignore");
+ return 0;
+ }
+
+ if (route->type == OSPF6_DEST_TYPE_ROUTER)
+ {
+ if (ADV_ROUTER_IN_PREFIX (&route->prefix) == area->ospf6->router_id)
+ {
+ inet_ntop (AF_INET, &(ADV_ROUTER_IN_PREFIX (&route->prefix)), buf,
+ sizeof (buf));
+ zlog_debug ("%s: Skipping ASBR announcement for ABR (%s)", __func__,
+ buf);
+ return 0;
+ }
+ }
+
if (route->type == OSPF6_DEST_TYPE_ROUTER)
{
if (IS_OSPF6_DEBUG_ABR || IS_OSPF6_DEBUG_ORIGINATE (INTER_ROUTER))
@@ -192,76 +245,62 @@ ospf6_abr_originate_summary_to_area (struct ospf6_route *route,
{
if (is_debug)
zlog_debug ("The route has just removed, purge previous LSA");
- if (summary)
- ospf6_route_remove (summary, summary_table);
- if (old)
- ospf6_lsa_purge (old);
- return;
- }
- /* 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_debug)
- zlog_debug ("Route type is none of network, range nor ASBR, withdraw");
- if (summary)
- ospf6_route_remove (summary, summary_table);
- if (old)
- ospf6_lsa_purge (old);
- return;
- }
+ if (route->type == OSPF6_DEST_TYPE_RANGE)
+ {
+ /* Whether the route have active longer prefix */
+ if (! CHECK_FLAG (route->flag, OSPF6_ROUTE_ACTIVE_SUMMARY))
+ {
+ if (is_debug)
+ zlog_debug ("The range is not active. withdraw");
+
+ ospf6_abr_delete_route (route, summary, summary_table, old);
+ }
+ }
+ else
+ if (old)
+ ospf6_lsa_purge (old);
- /* AS External routes are never considered */
- if (route->path.type == OSPF6_PATH_TYPE_EXTERNAL1 ||
- route->path.type == OSPF6_PATH_TYPE_EXTERNAL2)
- {
- if (is_debug)
- zlog_debug ("Path type is external, withdraw");
- if (summary)
- ospf6_route_remove (summary, summary_table);
- if (old)
- ospf6_lsa_purge (old);
- return;
+ return 0;
}
- /* do not generate if the path's area is the same as target area */
- if (route->path.area_id == area->area_id)
+ if ((route->type == OSPF6_DEST_TYPE_ROUTER) && IS_AREA_STUB(area))
{
if (is_debug)
- zlog_debug ("The route is in the area itself, ignore");
- if (summary)
- ospf6_route_remove (summary, summary_table);
- if (old)
- ospf6_lsa_purge (old);
- return;
+ zlog_debug ("Area has been stubbed, purge Inter-Router LSA");
+
+ ospf6_abr_delete_route (route, summary, summary_table, old);
+ return 0;
}
- /* 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)
+ if (area->no_summary && (route->path.subtype != OSPF6_PATH_SUBTYPE_DEFAULT_RT))
{
if (is_debug)
- zlog_debug ("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;
+ zlog_debug ("Area has been stubbed, purge prefix LSA");
+
+ ospf6_abr_delete_route (route, summary, summary_table, old);
+ return 0;
}
/* do not generate if the route cost is greater or equal to LSInfinity */
if (route->path.cost >= OSPF_LS_INFINITY)
{
- if (is_debug)
- zlog_debug ("The cost exceeds LSInfinity, withdraw");
- if (summary)
- ospf6_route_remove (summary, summary_table);
- if (old)
- ospf6_lsa_purge (old);
- return;
+ /* When we're clearing the range route because all active prefixes
+ * under the range are gone, we set the range's cost to
+ * OSPF_AREA_RANGE_COST_UNSPEC, which is > OSPF_LS_INFINITY. We
+ * don't want to trigger the code here for that. This code is for
+ * handling routes that have gone to infinity. The range removal happens
+ * elsewhere.
+ */
+ if ((route->type != OSPF6_DEST_TYPE_RANGE) &&
+ (route->path.cost != OSPF_AREA_RANGE_COST_UNSPEC))
+ {
+ if (is_debug)
+ zlog_debug ("The cost exceeds LSInfinity, withdraw");
+ if (old)
+ ospf6_lsa_purge (old);
+ return 0;
+ }
}
/* if this is a route to ASBR */
@@ -272,11 +311,8 @@ ospf6_abr_originate_summary_to_area (struct ospf6_route *route,
{
if (is_debug)
zlog_debug ("This is the secondary path to the ASBR, ignore");
- if (summary)
- ospf6_route_remove (summary, summary_table);
- if (old)
- ospf6_lsa_purge (old);
- return;
+ ospf6_abr_delete_route (route, summary, summary_table, old);
+ return 0;
}
/* Do not generate if the area is stub */
@@ -305,12 +341,8 @@ ospf6_abr_originate_summary_to_area (struct ospf6_route *route,
zlog_debug ("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;
+ ospf6_abr_delete_route (route, summary, summary_table, old);
+ return 0;
}
}
@@ -322,23 +354,17 @@ ospf6_abr_originate_summary_to_area (struct ospf6_route *route,
{
if (is_debug)
zlog_debug ("This is the range with DoNotAdvertise set. ignore");
- if (summary)
- ospf6_route_remove (summary, summary_table);
- if (old)
- ospf6_lsa_purge (old);
- return;
+ ospf6_abr_delete_route (route, summary, summary_table, old);
+ return 0;
}
- /* Whether the route have active longer prefix */
+ /* If there are no active prefixes in this range, remove */
if (! CHECK_FLAG (route->flag, OSPF6_ROUTE_ACTIVE_SUMMARY))
{
if (is_debug)
zlog_debug ("The range is not active. withdraw");
- if (summary)
- ospf6_route_remove (summary, summary_table);
- if (old)
- ospf6_lsa_purge (old);
- return;
+ ospf6_abr_delete_route (route, summary, summary_table, old);
+ return 0;
}
}
@@ -359,7 +385,7 @@ ospf6_abr_originate_summary_to_area (struct ospf6_route *route,
buf, sizeof(buf));
zlog_debug ("prefix %s was denied by export list", buf);
}
- return;
+ return 0;
}
}
@@ -380,7 +406,7 @@ ospf6_abr_originate_summary_to_area (struct ospf6_route *route,
buf, sizeof (buf));
zlog_debug ("prefix %s was denied by filter-list out", buf);
}
- return;
+ return 0;
}
}
@@ -388,15 +414,23 @@ ospf6_abr_originate_summary_to_area (struct ospf6_route *route,
if (summary == NULL)
{
summary = ospf6_route_copy (route);
- 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);
+
+ if (route->type == OSPF6_DEST_TYPE_ROUTER)
+ {
+ summary->path.origin.type = htons (OSPF6_LSTYPE_INTER_ROUTER);
+ summary->path.origin.id = ADV_ROUTER_IN_PREFIX (&route->prefix);
+ }
+ else
+ {
+ summary->path.origin.type = htons (OSPF6_LSTYPE_INTER_PREFIX);
+ if (route->type == OSPF6_DEST_TYPE_RANGE)
+ summary->path.origin.id = route->linkstate_id;
+ else
+ summary->path.origin.id =
+ ospf6_new_ls_id (summary->path.origin.type,
+ summary->path.origin.adv_router, area->lsdb);
+ }
summary = ospf6_route_add (summary, summary_table);
}
else
@@ -412,8 +446,9 @@ ospf6_abr_originate_summary_to_area (struct ospf6_route *route,
summary->path.prefix_options = route->path.prefix_options;
summary->path.area_id = area->area_id;
summary->path.type = OSPF6_PATH_TYPE_INTER;
+ summary->path.subtype = route->path.subtype;
summary->path.cost = route->path.cost;
- summary->nexthop[0] = route->nexthop[0];
+ /* summary->nexthop[0] = route->nexthop[0]; */
/* prepare buffer */
memset (buffer, 0, sizeof (buffer));
@@ -470,35 +505,138 @@ ospf6_abr_originate_summary_to_area (struct ospf6_route *route,
/* Originate */
ospf6_lsa_originate_area (lsa, area);
+
+ return 1;
+}
+
+void
+ospf6_abr_range_reset_cost (struct ospf6 *ospf6)
+{
+ struct listnode *node, *nnode;
+ struct ospf6_area *oa;
+ struct ospf6_route *range;
+
+ for (ALL_LIST_ELEMENTS (ospf6->area_list, node, nnode, oa))
+ for (range = ospf6_route_head (oa->range_table); range;
+ range = ospf6_route_next (range))
+ OSPF6_ABR_RANGE_CLEAR_COST(range);
+}
+
+static inline u_int32_t
+ospf6_abr_range_compute_cost (struct ospf6_route *range, struct ospf6 *o)
+{
+ struct ospf6_route *ro;
+ u_int32_t cost = 0;
+
+ for (ro = ospf6_route_match_head (&range->prefix, o->route_table);
+ ro; ro = ospf6_route_match_next (&range->prefix, ro))
+ {
+ if (ro->path.area_id == range->path.area_id &&
+ (ro->path.type == OSPF6_PATH_TYPE_INTRA) &&
+ ! CHECK_FLAG (ro->flag, OSPF6_ROUTE_REMOVE))
+ cost = MAX (cost, ro->path.cost);
+ }
+
+ return cost;
+}
+
+static inline int
+ospf6_abr_range_summary_needs_update (struct ospf6_route *range,
+ u_int32_t cost)
+{
+ int redo_summary = 0;
+
+ if (CHECK_FLAG(range->flag, OSPF6_ROUTE_REMOVE))
+ {
+ UNSET_FLAG (range->flag, OSPF6_ROUTE_ACTIVE_SUMMARY);
+ redo_summary = 1;
+ }
+ else if (CHECK_FLAG (range->flag, OSPF6_ROUTE_DO_NOT_ADVERTISE))
+ {
+ if (range->path.cost != 0)
+ {
+ range->path.cost = 0;
+ redo_summary = 1;
+ }
+ }
+ else if (cost)
+ {
+ if ((OSPF6_PATH_COST_IS_CONFIGURED(range->path) &&
+ range->path.cost != range->path.u.cost_config))
+ {
+ range->path.cost = range->path.u.cost_config;
+ SET_FLAG (range->flag, OSPF6_ROUTE_ACTIVE_SUMMARY);
+ redo_summary = 1;
+ }
+ else if (!OSPF6_PATH_COST_IS_CONFIGURED(range->path) &&
+ range->path.cost != cost)
+ {
+ range->path.cost = cost;
+ SET_FLAG (range->flag, OSPF6_ROUTE_ACTIVE_SUMMARY);
+ redo_summary = 1;
+ }
+ }
+ else if (CHECK_FLAG (range->flag, OSPF6_ROUTE_ACTIVE_SUMMARY))
+ {
+ /* Cost is zero, meaning no active range */
+ UNSET_FLAG (range->flag, OSPF6_ROUTE_ACTIVE_SUMMARY);
+ range->path.cost = OSPF_AREA_RANGE_COST_UNSPEC;
+ redo_summary = 1;
+ }
+
+ return (redo_summary);
}
static void
ospf6_abr_range_update (struct ospf6_route *range)
{
u_int32_t cost = 0;
- struct ospf6_route *ro;
+ struct listnode *node, *nnode;
+ struct ospf6_area *oa;
+ int summary_orig = 0;
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))
+ cost = ospf6_abr_range_compute_cost (range, ospf6);
+
+ /* Non-zero cost is a proxy for active longer prefixes in this range.
+ * If there are active routes covered by this range AND either the configured
+ * cost has changed or the summarized cost has changed then redo summaries.
+ * Alternately, if there are no longer active prefixes and there are
+ * summary announcements, withdraw those announcements.
+ *
+ * The don't advertise code relies on the path.cost being set to UNSPEC to
+ * work the first time. Subsequent times the path.cost is not 0 anyway if there
+ * were active ranges.
+ */
+
+ if (ospf6_abr_range_summary_needs_update (range, cost))
{
- if (ro->path.area_id == range->path.area_id &&
- ! CHECK_FLAG (ro->flag, OSPF6_ROUTE_REMOVE))
- cost = MAX (cost, ro->path.cost);
- }
+ for (ALL_LIST_ELEMENTS (ospf6->area_list, node, nnode, oa))
+ summary_orig += ospf6_abr_originate_summary_to_area (range, oa);
- if (range->path.cost != cost)
- {
- range->path.cost = cost;
+ if (CHECK_FLAG (range->flag, OSPF6_ROUTE_ACTIVE_SUMMARY) && summary_orig)
+ {
+ if (! CHECK_FLAG (range->flag, OSPF6_ROUTE_BLACKHOLE_ADDED))
+ {
+ if (IS_OSPF6_DEBUG_ABR)
+ zlog_debug ("Add discard route");
- if (range->path.cost)
- SET_FLAG (range->flag, OSPF6_ROUTE_ACTIVE_SUMMARY);
+ ospf6_zebra_add_discard (range);
+ }
+ }
else
- UNSET_FLAG (range->flag, OSPF6_ROUTE_ACTIVE_SUMMARY);
-
- ospf6_abr_originate_summary (range);
+ {
+ /* Summary removed or no summary generated as no specifics exist */
+ if (CHECK_FLAG (range->flag, OSPF6_ROUTE_BLACKHOLE_ADDED))
+ {
+ if (IS_OSPF6_DEBUG_ABR)
+ zlog_debug ("Delete discard route");
+
+ ospf6_zebra_delete_discard (range);
+ }
+ }
}
}
@@ -514,13 +652,63 @@ ospf6_abr_originate_summary (struct ospf6_route *route)
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);
+ {
+ ospf6_abr_range_update (range);
+ }
}
for (ALL_LIST_ELEMENTS (ospf6->area_list, node, nnode, oa))
ospf6_abr_originate_summary_to_area (route, oa);
}
+void
+ospf6_abr_defaults_to_stub (struct ospf6 *o)
+{
+ struct listnode *node, *nnode;
+ struct ospf6_area *oa;
+ struct ospf6_route *def, *route;
+
+ if (!o->backbone)
+ return;
+
+ def = ospf6_route_create();
+ def->type = OSPF6_DEST_TYPE_NETWORK;
+ def->prefix.family = AF_INET6;
+ def->prefix.prefixlen = 0;
+ memset (&def->prefix.u.prefix6, 0, sizeof(struct in6_addr));
+ def->type = OSPF6_DEST_TYPE_NETWORK;
+ def->path.type = OSPF6_PATH_TYPE_INTER;
+ def->path.subtype = OSPF6_PATH_SUBTYPE_DEFAULT_RT;
+ def->path.area_id = o->backbone->area_id;
+
+ for (ALL_LIST_ELEMENTS (ospf6->area_list, node, nnode, oa))
+ {
+ if (!IS_AREA_STUB (oa))
+ {
+ /* withdraw defaults when an area switches from stub to non-stub */
+ route = ospf6_route_lookup (&def->prefix, oa->summary_prefix);
+ if (route && (route->path.subtype == def->path.subtype))
+ {
+ if (IS_OSPF6_DEBUG_ABR)
+ zlog_debug ("Withdrawing default route from non-stubby area %s",
+ oa->name);
+ SET_FLAG (def->flag, OSPF6_ROUTE_REMOVE);
+ ospf6_abr_originate_summary_to_area (def, oa);
+ }
+ }
+ else
+ {
+ /* announce defaults to stubby areas */
+ if (IS_OSPF6_DEBUG_ABR)
+ zlog_debug ("Announcing default route into stubby area %s",
+ oa->name);
+ UNSET_FLAG (def->flag, OSPF6_ROUTE_REMOVE);
+ ospf6_abr_originate_summary_to_area (def, oa);
+ }
+ }
+ ospf6_route_delete (def);
+}
+
/* RFC 2328 16.2. Calculating the inter-area routes */
void
ospf6_abr_examin_summary (struct ospf6_lsa *lsa, struct ospf6_area *oa)
@@ -534,7 +722,6 @@ ospf6_abr_examin_summary (struct ospf6_lsa *lsa, struct ospf6_area *oa)
u_int8_t prefix_options = 0;
u_int32_t cost = 0;
u_char router_bits = 0;
- int i;
char buf[64];
int is_debug = 0;
struct ospf6_inter_prefix_lsa *prefix_lsa = NULL;
@@ -575,6 +762,7 @@ ospf6_abr_examin_summary (struct ospf6_lsa *lsa, struct ospf6_area *oa)
ospf6_linkstate_prefix (router_lsa->router_id, htonl (0), &prefix);
if (is_debug)
inet_ntop (AF_INET, &router_lsa->router_id, buf, sizeof (buf));
+
table = oa->ospf6->brouter_table;
type = OSPF6_DEST_TYPE_ROUTER;
options[0] = router_lsa->options[0];
@@ -600,6 +788,8 @@ ospf6_abr_examin_summary (struct ospf6_lsa *lsa, struct ospf6_area *oa)
old = route;
route = ospf6_route_next (route);
}
+ if (route)
+ ospf6_route_unlock (route);
/* (1) if cost == LSInfinity or if the LSA is MaxAge */
if (cost == OSPF_LS_INFINITY)
@@ -666,8 +856,22 @@ ospf6_abr_examin_summary (struct ospf6_lsa *lsa, struct ospf6_area *oa)
zlog_debug ("Prefix has NU/LA bit set, ignore");
if (old)
ospf6_route_remove (old, table);
+
return;
}
+ /* Avoid infinite recursion if someone has maliciously announced an
+ Inter-Router LSA for an ABR
+ */
+ if (lsa->header->adv_router == router_lsa->router_id)
+ {
+ if (is_debug)
+ zlog_debug ("Ignorning Inter-Router LSA for an ABR (%s)",
+ buf);
+ if (old)
+ ospf6_route_remove (old, table);
+
+ return;
+ }
}
/* (4) if the routing table entry for the ABR does not exist */
@@ -718,7 +922,7 @@ ospf6_abr_examin_summary (struct ospf6_lsa *lsa, struct ospf6_area *oa)
}
}
- /* (5),(6),(7) the path preference is handled by the sorting
+ /* (5),(6): the path preference is handled by the sorting
in the routing table. Always install the path by substituting
old route (if any). */
if (old)
@@ -739,12 +943,33 @@ ospf6_abr_examin_summary (struct ospf6_lsa *lsa, struct ospf6_area *oa)
route->path.area_id = oa->area_id;
route->path.type = OSPF6_PATH_TYPE_INTER;
route->path.cost = abr_entry->path.cost + cost;
- for (i = 0; i < OSPF6_MULTI_PATH_LIMIT; i++)
- route->nexthop[i] = abr_entry->nexthop[i];
- if (is_debug)
- zlog_debug ("Install route: %s", buf);
- ospf6_route_add (route, table);
+ ospf6_route_copy_nexthops (route, abr_entry);
+
+ /* (7) If the routes are identical, copy the next hops over to existing
+ route. ospf6's route table implementation will otherwise string both
+ routes, but keep the older one as the best route since the routes
+ are identical.
+ */
+ old = ospf6_route_lookup (&prefix, table);
+
+ if (old && (ospf6_route_cmp (route, old) == 0))
+ {
+ ospf6_route_merge_nexthops (old, route);
+ /* Update RIB/FIB */
+ if (table->hook_add)
+ (*table->hook_add) (old);
+
+ /* Delete new route */
+ ospf6_route_delete (route);
+ }
+ else
+ {
+ if (is_debug)
+ zlog_debug ("Install route: %s", buf);
+ /* ospf6_ia_add_nw_route (table, &prefix, route); */
+ ospf6_route_add (route, table);
+ }
}
void
@@ -752,21 +977,22 @@ ospf6_abr_examin_brouter (u_int32_t router_id)
{
struct ospf6_lsa *lsa;
struct ospf6_area *oa;
- struct listnode *node, *nnode;
u_int16_t type;
- for (ALL_LIST_ELEMENTS (ospf6->area_list, node, nnode, oa))
- {
- type = htons (OSPF6_LSTYPE_INTER_ROUTER);
- for (lsa = ospf6_lsdb_type_router_head (type, router_id, oa->lsdb); lsa;
- lsa = ospf6_lsdb_type_router_next (type, router_id, lsa))
- ospf6_abr_examin_summary (lsa, oa);
+ if (ospf6_is_router_abr (ospf6))
+ oa = ospf6->backbone;
+ else
+ oa = listgetdata(listhead(ospf6->area_list));
- type = htons (OSPF6_LSTYPE_INTER_PREFIX);
- for (lsa = ospf6_lsdb_type_router_head (type, router_id, oa->lsdb); lsa;
- lsa = ospf6_lsdb_type_router_next (type, router_id, lsa))
- ospf6_abr_examin_summary (lsa, oa);
- }
+ type = htons (OSPF6_LSTYPE_INTER_ROUTER);
+ for (lsa = ospf6_lsdb_type_router_head (type, router_id, oa->lsdb); lsa;
+ lsa = ospf6_lsdb_type_router_next (type, router_id, lsa))
+ ospf6_abr_examin_summary (lsa, oa);
+
+ type = htons (OSPF6_LSTYPE_INTER_PREFIX);
+ for (lsa = ospf6_lsdb_type_router_head (type, router_id, oa->lsdb); lsa;
+ lsa = ospf6_lsdb_type_router_next (type, router_id, lsa))
+ ospf6_abr_examin_summary (lsa, oa);
}
void
@@ -786,6 +1012,21 @@ ospf6_abr_reimport (struct ospf6_area *oa)
ospf6_abr_examin_summary (lsa, oa);
}
+void
+ospf6_abr_prefix_resummarize (struct ospf6 *o)
+{
+ struct ospf6_route *route;
+
+ if (IS_OSPF6_DEBUG_ABR)
+ zlog_debug ("Re-examining Inter-Prefix Summaries");
+
+ for (route = ospf6_route_head (o->route_table); route;
+ route = ospf6_route_next (route))
+ ospf6_abr_originate_summary(route);
+
+ if (IS_OSPF6_DEBUG_ABR)
+ zlog_debug ("Finished re-examining Inter-Prefix Summaries");
+}
/* Display functions */
diff --git a/ospf6d/ospf6_abr.h b/ospf6d/ospf6_abr.h
index e5e2660b..5bc2469e 100644
--- a/ospf6d/ospf6_abr.h
+++ b/ospf6d/ospf6_abr.h
@@ -59,17 +59,22 @@ struct ospf6_inter_router_lsa
{ (E)->metric &= htonl (0x00000000); \
(E)->metric |= htonl (0x00ffffff) & htonl (C); }
+#define OSPF6_ABR_RANGE_CLEAR_COST(range) (range->path.cost = OSPF_AREA_RANGE_COST_UNSPEC)
+
extern int ospf6_is_router_abr (struct ospf6 *o);
extern void ospf6_abr_enable_area (struct ospf6_area *oa);
extern void ospf6_abr_disable_area (struct ospf6_area *oa);
-extern void ospf6_abr_originate_summary_to_area (struct ospf6_route *route,
+extern int ospf6_abr_originate_summary_to_area (struct ospf6_route *route,
struct ospf6_area *area);
extern void ospf6_abr_originate_summary (struct ospf6_route *route);
extern void ospf6_abr_examin_summary (struct ospf6_lsa *lsa, struct ospf6_area *oa);
+extern void ospf6_abr_defaults_to_stub (struct ospf6 *);
extern void ospf6_abr_examin_brouter (u_int32_t router_id);
extern void ospf6_abr_reimport (struct ospf6_area *oa);
+extern void ospf6_abr_range_reset_cost (struct ospf6 *ospf6);
+extern void ospf6_abr_prefix_resummarize (struct ospf6 *ospf6);
extern int config_write_ospf6_debug_abr (struct vty *vty);
extern void install_element_ospf6_debug_abr (void);
diff --git a/ospf6d/ospf6_area.c b/ospf6d/ospf6_area.c
index 9b704221..71787541 100644
--- a/ospf6d/ospf6_area.c
+++ b/ospf6d/ospf6_area.c
@@ -43,6 +43,7 @@
#include "ospf6_interface.h"
#include "ospf6_intra.h"
#include "ospf6_abr.h"
+#include "ospf6_asbr.h"
#include "ospf6d.h"
int
@@ -133,12 +134,82 @@ ospf6_area_route_hook_remove (struct ospf6_route *route)
ospf6_route_remove (copy, ospf6->route_table);
}
+static void
+ospf6_area_stub_update (struct ospf6_area *area)
+{
+
+ if (IS_AREA_STUB (area))
+ {
+ if (IS_OSPF6_DEBUG_ORIGINATE (ROUTER))
+ zlog_debug ("Stubbing out area for if %s\n", area->name);
+ OSPF6_OPT_CLEAR (area->options, OSPF6_OPT_E);
+ }
+ else if (IS_AREA_ENABLED (area))
+ {
+ if (IS_OSPF6_DEBUG_ORIGINATE (ROUTER))
+ zlog_debug ("Normal area for if %s\n", area->name);
+ OSPF6_OPT_SET (area->options, OSPF6_OPT_E);
+ ospf6_asbr_send_externals_to_area (area);
+ }
+
+ OSPF6_ROUTER_LSA_SCHEDULE(area);
+}
+
+static int
+ospf6_area_stub_set (struct ospf6 *ospf6, struct ospf6_area *area)
+{
+ if (!IS_AREA_STUB(area))
+ {
+ SET_FLAG (area->flag, OSPF6_AREA_STUB);
+ ospf6_area_stub_update (area);
+ }
+
+ return (1);
+}
+
+static void
+ospf6_area_stub_unset (struct ospf6 *ospf6, struct ospf6_area *area)
+{
+ if (IS_AREA_STUB (area))
+ {
+ UNSET_FLAG (area->flag, OSPF6_AREA_STUB);
+ ospf6_area_stub_update (area);
+ }
+}
+
+static void
+ospf6_area_no_summary_set (struct ospf6 *ospf6, struct ospf6_area *area)
+{
+ if (area)
+ {
+ if (!area->no_summary)
+ {
+ area->no_summary = 1;
+ ospf6_abr_range_reset_cost (ospf6);
+ ospf6_abr_prefix_resummarize (ospf6);
+ }
+ }
+}
+
+static void
+ospf6_area_no_summary_unset (struct ospf6 *ospf6, struct ospf6_area *area)
+{
+ if (area)
+ {
+ if (area->no_summary)
+ {
+ area->no_summary = 0;
+ ospf6_abr_range_reset_cost (ospf6);
+ ospf6_abr_prefix_resummarize (ospf6);
+ }
+ }
+}
+
/* Make new area structure */
struct ospf6_area *
ospf6_area_create (u_int32_t area_id, struct ospf6 *o)
{
struct ospf6_area *oa;
- struct ospf6_route *route;
oa = XCALLOC (MTYPE_OSPF6_AREA, sizeof (struct ospf6_area));
@@ -160,6 +231,7 @@ ospf6_area_create (u_int32_t area_id, struct ospf6 *o)
oa->range_table = OSPF6_ROUTE_TABLE_CREATE (AREA, PREFIX_RANGES);
oa->range_table->scope = oa;
+ bf_init(oa->range_table->idspace, 32);
oa->summary_prefix = OSPF6_ROUTE_TABLE_CREATE (AREA, SUMMARY_PREFIXES);
oa->summary_prefix->scope = oa;
oa->summary_router = OSPF6_ROUTE_TABLE_CREATE (AREA, SUMMARY_ROUTERS);
@@ -179,13 +251,16 @@ ospf6_area_create (u_int32_t area_id, struct ospf6 *o)
OSPF6_OPT_SET (oa->options, OSPF6_OPT_E);
+ SET_FLAG (oa->flag, OSPF6_AREA_ACTIVE);
+ SET_FLAG (oa->flag, OSPF6_AREA_ENABLE);
+
oa->ospf6 = o;
listnode_add_sort (o->area_list, oa);
- /* import athoer area's routes as inter-area routes */
- for (route = ospf6_route_head (o->route_table); route;
- route = ospf6_route_next (route))
- ospf6_abr_originate_summary_to_area (route, oa);
+ if (area_id == OSPF_AREA_BACKBONE)
+ {
+ o->backbone = oa;
+ }
return oa;
}
@@ -196,10 +271,6 @@ ospf6_area_delete (struct ospf6_area *oa)
struct listnode *n;
struct ospf6_interface *oi;
- ospf6_route_table_delete (oa->range_table);
- ospf6_route_table_delete (oa->summary_prefix);
- ospf6_route_table_delete (oa->summary_router);
-
/* The ospf6_interface structs store configuration
* information which should not be lost/reset when
* deleting an area.
@@ -217,8 +288,9 @@ ospf6_area_delete (struct ospf6_area *oa)
ospf6_route_table_delete (oa->spf_table);
ospf6_route_table_delete (oa->route_table);
- THREAD_OFF (oa->thread_spf_calculation);
- THREAD_OFF (oa->thread_route_calculation);
+ ospf6_route_table_delete (oa->range_table);
+ ospf6_route_table_delete (oa->summary_prefix);
+ ospf6_route_table_delete (oa->summary_router);
listnode_delete (oa->ospf6->area_list, oa);
oa->ospf6 = NULL;
@@ -281,9 +353,6 @@ ospf6_area_disable (struct ospf6_area *oa)
ospf6_spf_table_finish(oa->spf_table);
ospf6_route_remove_all(oa->route_table);
- THREAD_OFF (oa->thread_spf_calculation);
- THREAD_OFF (oa->thread_route_calculation);
-
THREAD_OFF (oa->thread_router_lsa);
THREAD_OFF (oa->thread_intra_prefix_lsa);
}
@@ -294,16 +363,46 @@ ospf6_area_show (struct vty *vty, struct ospf6_area *oa)
{
struct listnode *i;
struct ospf6_interface *oi;
+ unsigned long result;
- vty_out (vty, " Area %s%s", oa->name, VNL);
+ if (!IS_AREA_STUB (oa))
+ vty_out (vty, " Area %s%s", oa->name, VNL);
+ else
+ {
+ if (oa->no_summary)
+ {
+ vty_out (vty, " Area %s[Stub, No Summary]%s", oa->name, VNL);
+ }
+ else
+ {
+ vty_out (vty, " Area %s[Stub]%s", oa->name, VNL);
+ }
+ }
vty_out (vty, " Number of Area scoped LSAs is %u%s",
oa->lsdb->count, VNL);
vty_out (vty, " Interface attached to this area:");
for (ALL_LIST_ELEMENTS_RO (oa->if_list, i, oi))
vty_out (vty, " %s", oi->interface->name);
-
vty_out (vty, "%s", VNL);
+
+ if (oa->ts_spf.tv_sec || oa->ts_spf.tv_usec)
+ {
+ result = timeval_elapsed (recent_relative_time (), oa->ts_spf);
+ if (result/TIMER_SECOND_MICRO > 0)
+ {
+ vty_out (vty, "SPF last executed %ld.%lds ago%s",
+ result/TIMER_SECOND_MICRO,
+ result%TIMER_SECOND_MICRO, VTY_NEWLINE);
+ }
+ else
+ {
+ vty_out (vty, "SPF last executed %ldus ago%s",
+ result, VTY_NEWLINE);
+ }
+ }
+ else
+ vty_out (vty, "SPF has not been run%s", VTY_NEWLINE);
}
@@ -347,19 +446,16 @@ DEFUN (area_range,
struct ospf6_area *oa;
struct prefix prefix;
struct ospf6_route *range;
+ u_int32_t cost = OSPF_AREA_RANGE_COST_UNSPEC;
OSPF6_CMD_AREA_GET (argv[0], oa);
- argc--;
- argv++;
- ret = str2prefix (argv[0], &prefix);
+ ret = str2prefix (argv[1], &prefix);
if (ret != 1 || prefix.family != AF_INET6)
{
- vty_out (vty, "Malformed argument: %s%s", argv[0], VNL);
+ vty_out (vty, "Malformed argument: %s%s", argv[1], VNL);
return CMD_SUCCESS;
}
- argc--;
- argv++;
range = ospf6_route_lookup (&prefix, oa->range_table);
if (range == NULL)
@@ -367,23 +463,43 @@ DEFUN (area_range,
range = ospf6_route_create ();
range->type = OSPF6_DEST_TYPE_RANGE;
range->prefix = prefix;
+ range->path.area_id = oa->area_id;
+ range->path.cost = OSPF_AREA_RANGE_COST_UNSPEC;
+ range->linkstate_id =
+ (u_int32_t) htonl(ospf6_new_range_ls_id (oa->range_table));
}
- if (argc)
+ if (argc > 2)
{
- if (! strcmp (argv[0], "not-advertise"))
- SET_FLAG (range->flag, OSPF6_ROUTE_DO_NOT_ADVERTISE);
- else if (! strcmp (argv[0], "advertise"))
- UNSET_FLAG (range->flag, OSPF6_ROUTE_DO_NOT_ADVERTISE);
+ if (strcmp (argv[2], "not-advertise") == 0)
+ {
+ SET_FLAG (range->flag, OSPF6_ROUTE_DO_NOT_ADVERTISE);
+ }
+ else if (strcmp (argv[2], "advertise") == 0)
+ {
+ UNSET_FLAG (range->flag, OSPF6_ROUTE_DO_NOT_ADVERTISE);
+ }
+ else
+ {
+ VTY_GET_INTEGER_RANGE ("cost", cost, argv[2], 0, OSPF_LS_INFINITY);
+ UNSET_FLAG (range->flag, OSPF6_ROUTE_DO_NOT_ADVERTISE);
+ }
}
- if (range->rnode)
+ range->path.u.cost_config = cost;
+
+ zlog_debug ("%s: for prefix %s, flag = %x\n", __func__, argv[1], range->flag);
+ if (range->rnode == NULL)
{
- vty_out (vty, "Range already defined: %s%s", argv[-1], VNL);
- return CMD_WARNING;
+ ospf6_route_add (range, oa->range_table);
+ }
+
+ if (ospf6_is_router_abr (ospf6))
+ {
+ /* Redo summaries if required */
+ ospf6_abr_prefix_resummarize (ospf6);
}
- ospf6_route_add (range, oa->range_table);
return CMD_SUCCESS;
}
@@ -396,6 +512,26 @@ ALIAS (area_range,
"Specify IPv6 prefix\n"
)
+ALIAS (area_range,
+ area_range_cost_cmd,
+ "area (A.B.C.D|<0-4294967295>) range X:X::X:X/M cost <0-16777215>",
+ "OSPF area parameters\n"
+ OSPF6_AREA_ID_STR
+ "Summarize routes matching address/mask (border routers only)\n"
+ "Area range prefix\n"
+ "User specified metric for this range\n"
+ "Advertised metric for this range\n")
+
+ALIAS (area_range,
+ area_range_advertise_cost_cmd,
+ "area (A.B.C.D|<0-4294967295>) range X:X::X:X/M advertise cost <0-16777215>",
+ "OSPF area parameters\n"
+ OSPF6_AREA_ID_STR
+ "Summarize routes matching address/mask (border routers only)\n"
+ "Area range prefix\n"
+ "User specified metric for this range\n"
+ "Advertised metric for this range\n")
+
DEFUN (no_area_range,
no_area_range_cmd,
"no area A.B.C.D range X:X::X:X/M",
@@ -408,7 +544,7 @@ DEFUN (no_area_range,
int ret;
struct ospf6_area *oa;
struct prefix prefix;
- struct ospf6_route *range;
+ struct ospf6_route *range, *route;
OSPF6_CMD_AREA_GET (argv[0], oa);
argc--;
@@ -428,6 +564,21 @@ DEFUN (no_area_range,
return CMD_SUCCESS;
}
+ if (ospf6_is_router_abr(oa->ospf6))
+ {
+ /* Blow away the aggregated LSA and route */
+ SET_FLAG (range->flag, OSPF6_ROUTE_REMOVE);
+
+ /* Redo summaries if required */
+ for (route = ospf6_route_head (ospf6->route_table); route;
+ route = ospf6_route_next (route))
+ ospf6_abr_originate_summary(route);
+
+ /* purge the old aggregated summary LSA */
+ ospf6_abr_originate_summary(range);
+ }
+ ospf6_release_range_ls_id(oa->range_table,
+ (u_int32_t) ntohl(range->linkstate_id));
ospf6_route_remove (range, oa->range_table);
return CMD_SUCCESS;
@@ -449,6 +600,13 @@ ospf6_area_config_write (struct vty *vty)
prefix2str (&range->prefix, buf, sizeof (buf));
vty_out (vty, " area %s range %s%s", oa->name, buf, VNL);
}
+ if (IS_AREA_STUB (oa))
+ {
+ if (oa->no_summary)
+ vty_out (vty, " area %s stub no-summary%s", oa->name, VNL);
+ else
+ vty_out (vty, " area %s stub%s", oa->name, VNL);
+ }
if (PREFIX_NAME_IN (oa))
vty_out (vty, " area %s filter-list prefix %s in%s",
oa->name, PREFIX_NAME_IN (oa), VNL);
@@ -666,6 +824,8 @@ DEFUN (show_ipv6_ospf6_spf_tree,
struct ospf6_route *route;
struct prefix prefix;
+ OSPF6_CMD_CHECK_RUNNING ();
+
ospf6_linkstate_prefix (ospf6->router_id, htonl (0), &prefix);
for (ALL_LIST_ELEMENTS_RO (ospf6->area_list, node, oa))
@@ -701,6 +861,8 @@ DEFUN (show_ipv6_ospf6_area_spf_tree,
struct ospf6_route *route;
struct prefix prefix;
+ OSPF6_CMD_CHECK_RUNNING ();
+
ospf6_linkstate_prefix (ospf6->router_id, htonl (0), &prefix);
if (inet_pton (AF_INET, argv[0], &area_id) != 1)
@@ -747,6 +909,8 @@ DEFUN (show_ipv6_ospf6_simulate_spf_tree_root,
struct ospf6_route_table *spf_table;
unsigned char tmp_debug_ospf6_spf = 0;
+ OSPF6_CMD_CHECK_RUNNING ();
+
inet_pton (AF_INET, argv[0], &router_id);
ospf6_linkstate_prefix (router_id, htonl (0), &prefix);
@@ -786,6 +950,94 @@ DEFUN (show_ipv6_ospf6_simulate_spf_tree_root,
return CMD_SUCCESS;
}
+DEFUN (ospf6_area_stub,
+ ospf6_area_stub_cmd,
+ "area (A.B.C.D|<0-4294967295>) stub",
+ "OSPF6 area parameters\n"
+ "OSPF6 area ID in IP address format\n"
+ "OSPF6 area ID as a decimal value\n"
+ "Configure OSPF6 area as stub\n")
+{
+ struct ospf6_area *area;
+
+ OSPF6_CMD_AREA_GET(argv[0], area);
+
+ if (!ospf6_area_stub_set (ospf6, area))
+ {
+ vty_out (vty, "First deconfigure all virtual link through this area%s",
+ VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ ospf6_area_no_summary_unset (ospf6, area);
+
+ return CMD_SUCCESS;
+}
+
+DEFUN (ospf6_area_stub_no_summary,
+ ospf6_area_stub_no_summary_cmd,
+ "area (A.B.C.D|<0-4294967295>) stub no-summary",
+ "OSPF6 stub parameters\n"
+ "OSPF6 area ID in IP address format\n"
+ "OSPF6 area ID as a decimal value\n"
+ "Configure OSPF6 area as stub\n"
+ "Do not inject inter-area routes into stub\n")
+{
+ struct ospf6_area *area;
+
+ OSPF6_CMD_AREA_GET(argv[0], area);
+
+ if (!ospf6_area_stub_set (ospf6, area))
+ {
+ vty_out (vty, "First deconfigure all virtual link through this area%s",
+ VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ ospf6_area_no_summary_set (ospf6, area);
+
+ return CMD_SUCCESS;
+}
+
+DEFUN (no_ospf6_area_stub,
+ no_ospf6_area_stub_cmd,
+ "no area (A.B.C.D|<0-4294967295>) stub",
+ NO_STR
+ "OSPF6 area parameters\n"
+ "OSPF6 area ID in IP address format\n"
+ "OSPF6 area ID as a decimal value\n"
+ "Configure OSPF6 area as stub\n")
+{
+ struct ospf6_area *area;
+
+ OSPF6_CMD_AREA_GET(argv[0], area);
+
+ ospf6_area_stub_unset (ospf6, area);
+ ospf6_area_no_summary_unset (ospf6, area);
+
+ return CMD_SUCCESS;
+}
+
+DEFUN (no_ospf6_area_stub_no_summary,
+ no_ospf6_area_stub_no_summary_cmd,
+ "no area (A.B.C.D|<0-4294967295>) stub no-summary",
+ NO_STR
+ "OSPF6 area parameters\n"
+ "OSPF6 area ID in IP address format\n"
+ "OSPF6 area ID as a decimal value\n"
+ "Configure OSPF6 area as stub\n"
+ "Do not inject inter-area routes into area\n")
+{
+ struct ospf6_area *area;
+
+ OSPF6_CMD_AREA_GET(argv[0], area);
+
+ ospf6_area_stub_unset (ospf6, area);
+ ospf6_area_no_summary_unset (ospf6, area);
+
+ return CMD_SUCCESS;
+}
+
void
ospf6_area_init (void)
{
@@ -799,7 +1051,14 @@ ospf6_area_init (void)
install_element (OSPF6_NODE, &area_range_cmd);
install_element (OSPF6_NODE, &area_range_advertise_cmd);
+ install_element (OSPF6_NODE, &area_range_cost_cmd);
+ install_element (OSPF6_NODE, &area_range_advertise_cost_cmd);
install_element (OSPF6_NODE, &no_area_range_cmd);
+ install_element (OSPF6_NODE, &ospf6_area_stub_no_summary_cmd);
+ install_element (OSPF6_NODE, &ospf6_area_stub_cmd);
+ install_element (OSPF6_NODE, &no_ospf6_area_stub_no_summary_cmd);
+ install_element (OSPF6_NODE, &no_ospf6_area_stub_cmd);
+
install_element (OSPF6_NODE, &area_import_list_cmd);
install_element (OSPF6_NODE, &no_area_import_list_cmd);
diff --git a/ospf6d/ospf6_area.h b/ospf6d/ospf6_area.h
index 655967a9..3b752d94 100644
--- a/ospf6d/ospf6_area.h
+++ b/ospf6d/ospf6_area.h
@@ -46,6 +46,9 @@ struct ospf6_area
struct ospf6_route_table *summary_prefix;
struct ospf6_route_table *summary_router;
+ /* Area type */
+ int no_summary;
+
/* OSPF interface list */
struct list *if_list;
@@ -55,8 +58,6 @@ struct ospf6_area
struct ospf6_route_table *spf_table;
struct ospf6_route_table *route_table;
- struct thread *thread_spf_calculation;
- struct thread *thread_route_calculation;
u_int32_t spf_calculation; /* SPF calculation count */
struct thread *thread_router_lsa;
@@ -98,6 +99,8 @@ struct ospf6_area
#define PREFIX_NAME_OUT(A) (A)->plist_out.name
#define PREFIX_LIST_OUT(A) (A)->plist_out.list
+ /* Time stamps. */
+ struct timeval ts_spf; /* SPF calculation time stamp. */
};
#define OSPF6_AREA_ENABLE 0x01
diff --git a/ospf6d/ospf6_asbr.c b/ospf6d/ospf6_asbr.c
index 6eca142d..136824bc 100644
--- a/ospf6d/ospf6_asbr.c
+++ b/ospf6d/ospf6_asbr.c
@@ -154,7 +154,6 @@ ospf6_asbr_lsa_add (struct ospf6_lsa *lsa)
struct prefix asbr_id;
struct ospf6_route *asbr_entry, *route;
char buf[64];
- int i;
external = (struct ospf6_as_external_lsa *)
OSPF6_LSA_HEADER_END (lsa->header);
@@ -213,18 +212,17 @@ ospf6_asbr_lsa_add (struct ospf6_lsa *lsa)
route->path.type = OSPF6_PATH_TYPE_EXTERNAL2;
route->path.metric_type = 2;
route->path.cost = asbr_entry->path.cost;
- route->path.cost_e2 = OSPF6_ASBR_METRIC (external);
+ route->path.u.cost_e2 = OSPF6_ASBR_METRIC (external);
}
else
{
route->path.type = OSPF6_PATH_TYPE_EXTERNAL1;
route->path.metric_type = 1;
route->path.cost = asbr_entry->path.cost + OSPF6_ASBR_METRIC (external);
- route->path.cost_e2 = 0;
+ route->path.u.cost_e2 = 0;
}
- for (i = 0; i < OSPF6_MULTI_PATH_LIMIT; i++)
- ospf6_nexthop_copy (&route->nexthop[i], &asbr_entry->nexthop[i]);
+ ospf6_route_copy_nexthops (route, asbr_entry);
if (IS_OSPF6_DEBUG_EXAMIN (AS_EXTERNAL))
{
@@ -240,7 +238,7 @@ ospf6_asbr_lsa_remove (struct ospf6_lsa *lsa)
{
struct ospf6_as_external_lsa *external;
struct prefix prefix;
- struct ospf6_route *route;
+ struct ospf6_route *route, *nroute;
char buf[64];
external = (struct ospf6_as_external_lsa *)
@@ -274,8 +272,9 @@ ospf6_asbr_lsa_remove (struct ospf6_lsa *lsa)
for (ospf6_route_lock (route);
route && ospf6_route_is_prefix (&prefix, route);
- route = ospf6_route_next (route))
+ route = nroute)
{
+ nroute = ospf6_route_next (route);
if (route->type != OSPF6_DEST_TYPE_NETWORK)
continue;
if (route->path.origin.type != lsa->header->type)
@@ -403,13 +402,29 @@ ospf6_asbr_redistribute_unset (int type)
if (info->type != type)
continue;
- ospf6_asbr_redistribute_remove (info->type, route->nexthop[0].ifindex,
- &route->prefix);
+ ospf6_asbr_redistribute_remove (info->type, 0, &route->prefix);
}
ospf6_asbr_routemap_unset (type);
}
+/* When an area is unstubified, flood all the external LSAs in the area */
+void
+ospf6_asbr_send_externals_to_area (struct ospf6_area *oa)
+{
+ struct ospf6_lsa *lsa;
+
+ for (lsa = ospf6_lsdb_head (oa->ospf6->lsdb); lsa;
+ lsa = ospf6_lsdb_next (lsa))
+ {
+ if (ntohs (lsa->header->type) == OSPF6_LSTYPE_AS_EXTERNAL)
+ {
+ zlog_debug ("%s: Flooding AS-External LSA %s\n", __func__, lsa->name);
+ ospf6_flood_area (NULL, lsa, oa);
+ }
+ }
+}
+
void
ospf6_asbr_redistribute_add (int type, ifindex_t ifindex, struct prefix *prefix,
u_int nexthop_num, struct in6_addr *nexthop)
@@ -483,9 +498,11 @@ ospf6_asbr_redistribute_add (int type, ifindex_t ifindex, struct prefix *prefix,
}
info->type = type;
- match->nexthop[0].ifindex = ifindex;
+
if (nexthop_num && nexthop)
- memcpy (&match->nexthop[0].address, nexthop, sizeof (struct in6_addr));
+ ospf6_route_add_nexthop (match, ifindex, nexthop);
+ else
+ ospf6_route_add_nexthop (match, ifindex, NULL);
/* create/update binding in external_id_table */
prefix_id.family = AF_INET;
@@ -528,9 +545,10 @@ ospf6_asbr_redistribute_add (int type, ifindex_t ifindex, struct prefix *prefix,
}
info->type = type;
- route->nexthop[0].ifindex = ifindex;
if (nexthop_num && nexthop)
- memcpy (&route->nexthop[0].address, nexthop, sizeof (struct in6_addr));
+ ospf6_route_add_nexthop (route, ifindex, nexthop);
+ else
+ ospf6_route_add_nexthop (route, ifindex, NULL);
/* create/update binding in external_id_table */
prefix_id.family = AF_INET;
@@ -680,6 +698,15 @@ DEFUN (no_ospf6_redistribute,
return CMD_SUCCESS;
}
+ALIAS (no_ospf6_redistribute,
+ no_ospf6_redistribute_route_map_cmd,
+ "no redistribute " QUAGGA_REDIST_STR_OSPF6D " route-map WORD",
+ NO_STR
+ "Redistribute\n"
+ QUAGGA_REDIST_HELP_STR_OSPF6D
+ "Route map reference\n"
+ "Route map name\n")
+
int
ospf6_redistribute_config_write (struct vty *vty)
{
@@ -968,13 +995,13 @@ route_map_command_status (struct vty *vty, int ret)
switch (ret)
{
case RMAP_RULE_MISSING:
- vty_out (vty, "Can't find rule.%s", VNL);
+ vty_out (vty, "OSPF6 Can't find rule.%s", VNL);
break;
case RMAP_COMPILE_ERROR:
- vty_out (vty, "Argument is malformed.%s", VNL);
+ vty_out (vty, "OSPF6 Argument is malformed.%s", VNL);
break;
default:
- vty_out (vty, "route-map add set failed.%s", VNL);
+ vty_out (vty, "OSPF6 route-map add set failed.%s", VNL);
break;
}
return CMD_WARNING;
@@ -1089,17 +1116,30 @@ DEFUN (set_metric,
/* delete "set metric" */
DEFUN (no_set_metric,
no_set_metric_cmd,
- "no set metric <0-4294967295>",
+ "no set metric",
NO_STR
- "Set value\n"
- "Metric\n"
- "METRIC value\n")
+ SET_STR
+ "Metric value for destination routing protocol\n")
{
- int ret = route_map_delete_set ((struct route_map_index *) vty->index,
- "metric", argv[0]);
+ int ret = 0;
+
+ if (argc == 0)
+ ret = route_map_delete_set ((struct route_map_index *) vty->index,
+ "metric", NULL);
+ else
+ ret = route_map_delete_set ((struct route_map_index *) vty->index,
+ "metric", argv[0]);
return route_map_command_status (vty, ret);
}
+ALIAS (no_set_metric,
+ no_set_metric_val_cmd,
+ "no set metric <0-4294967295>",
+ NO_STR
+ SET_STR
+ "Metric value for destination routing protocol\n"
+ "Metric value\n")
+
/* add "set forwarding-address" */
DEFUN (ospf6_routemap_set_forwarding,
ospf6_routemap_set_forwarding_cmd,
@@ -1158,6 +1198,7 @@ ospf6_routemap_init (void)
/* ASE Metric */
install_element (RMAP_NODE, &set_metric_cmd);
install_element (RMAP_NODE, &no_set_metric_cmd);
+ install_element (RMAP_NODE, &no_set_metric_val_cmd);
/* ASE Metric */
install_element (RMAP_NODE, &ospf6_routemap_set_forwarding_cmd);
@@ -1256,13 +1297,13 @@ ospf6_asbr_external_route_show (struct vty *vty, struct ospf6_route *route)
inet_ntop (AF_INET6, &info->forwarding, forwarding, sizeof (forwarding));
else
snprintf (forwarding, sizeof (forwarding), ":: (ifindex %d)",
- route->nexthop[0].ifindex);
+ ospf6_route_get_first_nh_index (route));
vty_out (vty, "%c %-32s %-15s type-%d %5lu %s%s",
zebra_route_char(info->type),
prefix, id, route->path.metric_type,
(u_long) (route->path.metric_type == 2 ?
- route->path.cost_e2 : route->path.cost),
+ route->path.u.cost_e2 : route->path.cost),
forwarding, VNL);
}
@@ -1277,6 +1318,8 @@ DEFUN (show_ipv6_ospf6_redistribute,
{
struct ospf6_route *route;
+ OSPF6_CMD_CHECK_RUNNING ();
+
ospf6_redistribute_show_config (vty);
for (route = ospf6_route_head (ospf6->external_table); route;
@@ -1308,6 +1351,7 @@ ospf6_asbr_init (void)
install_element (OSPF6_NODE, &ospf6_redistribute_cmd);
install_element (OSPF6_NODE, &ospf6_redistribute_routemap_cmd);
install_element (OSPF6_NODE, &no_ospf6_redistribute_cmd);
+ install_element (OSPF6_NODE, &no_ospf6_redistribute_route_map_cmd);
}
void
diff --git a/ospf6d/ospf6_asbr.h b/ospf6d/ospf6_asbr.h
index f3df90b1..645e8fd9 100644
--- a/ospf6d/ospf6_asbr.h
+++ b/ospf6d/ospf6_asbr.h
@@ -91,6 +91,7 @@ extern int ospf6_redistribute_config_write (struct vty *vty);
extern void ospf6_asbr_init (void);
extern void ospf6_asbr_redistribute_reset (void);
extern void ospf6_asbr_terminate (void);
+extern void ospf6_asbr_send_externals_to_area (struct ospf6_area *);
extern int config_write_ospf6_debug_asbr (struct vty *vty);
extern void install_element_ospf6_debug_asbr (void);
diff --git a/ospf6d/ospf6_flood.c b/ospf6d/ospf6_flood.c
index 815db7b7..82cf6a6c 100644
--- a/ospf6d/ospf6_flood.c
+++ b/ospf6d/ospf6_flood.c
@@ -422,7 +422,7 @@ ospf6_flood_interface (struct ospf6_neighbor *from,
}
}
-static void
+void
ospf6_flood_area (struct ospf6_neighbor *from,
struct ospf6_lsa *lsa, struct ospf6_area *oa)
{
@@ -892,6 +892,9 @@ ospf6_receive_lsa (struct ospf6_neighbor *from,
table calculation (replacing database copy) */
ospf6_install_lsa (new);
+ if (OSPF6_LSA_IS_MAXAGE (new))
+ ospf6_maxage_remove (from->ospf6_if->area->ospf6);
+
/* (e) possibly acknowledge */
ospf6_acknowledge_lsa (new, ismore_recent, from);
diff --git a/ospf6d/ospf6_flood.h b/ospf6d/ospf6_flood.h
index 3a6f300b..ba7fd25f 100644
--- a/ospf6d/ospf6_flood.h
+++ b/ospf6d/ospf6_flood.h
@@ -52,6 +52,8 @@ extern void ospf6_decrement_retrans_count (struct ospf6_lsa *lsa);
/* flooding & clear flooding */
extern void ospf6_flood_clear (struct ospf6_lsa *lsa);
extern void ospf6_flood (struct ospf6_neighbor *from, struct ospf6_lsa *lsa);
+extern void ospf6_flood_area (struct ospf6_neighbor *from,
+ struct ospf6_lsa *lsa, struct ospf6_area *oa);
/* receive & install */
extern void ospf6_receive_lsa (struct ospf6_neighbor *from,
diff --git a/ospf6d/ospf6_interface.c b/ospf6d/ospf6_interface.c
index 26f68ac5..a52da720 100644
--- a/ospf6d/ospf6_interface.c
+++ b/ospf6d/ospf6_interface.c
@@ -392,6 +392,7 @@ ospf6_interface_connected_route_update (struct interface *ifp)
struct ospf6_route *route;
struct connected *c;
struct listnode *node, *nnode;
+ struct in6_addr nh_addr;
oi = (struct ospf6_interface *) ifp->info;
if (oi == NULL)
@@ -447,8 +448,8 @@ ospf6_interface_connected_route_update (struct interface *ifp)
route->path.area_id = oi->area->area_id;
route->path.type = OSPF6_PATH_TYPE_INTRA;
route->path.cost = oi->cost;
- route->nexthop[0].ifindex = oi->interface->ifindex;
- inet_pton (AF_INET6, "::1", &route->nexthop[0].address);
+ inet_pton (AF_INET6, "::1", &nh_addr);
+ ospf6_route_add_nexthop (route, oi->interface->ifindex, &nh_addr);
ospf6_route_add (route, oi->route_connected);
}
@@ -728,7 +729,18 @@ interface_up (struct thread *thread)
}
/* Join AllSPFRouters */
- ospf6_sso (oi->interface->ifindex, &allspfrouters6, IPV6_JOIN_GROUP);
+ if (ospf6_sso (oi->interface->ifindex, &allspfrouters6, IPV6_JOIN_GROUP) < 0)
+ {
+ if (oi->sso_try_cnt++ < OSPF6_INTERFACE_SSO_RETRY_MAX)
+ {
+ zlog_info("Scheduling %s for sso retry, trial count: %d",
+ oi->interface->name, oi->sso_try_cnt);
+ thread_add_timer (master, interface_up, oi,
+ OSPF6_INTERFACE_SSO_RETRY_INT);
+ }
+ return 0;
+ }
+ oi->sso_try_cnt = 0; /* Reset on success */
/* Update interface route */
ospf6_interface_connected_route_update (oi->interface);
@@ -1915,6 +1927,66 @@ ospf6_interface_init (void)
install_element (OSPF6_NODE, &no_auto_cost_reference_bandwidth_cmd);
}
+/* Clear the specified interface structure */
+static void
+ospf6_interface_clear (struct vty *vty, struct interface *ifp)
+{
+ struct ospf6_interface *oi;
+
+ if (!if_is_operative (ifp))
+ return;
+
+ if (ifp->info == NULL)
+ return;
+
+ oi = (struct ospf6_interface *) ifp->info;
+
+ if (IS_OSPF6_DEBUG_INTERFACE)
+ zlog_debug ("Interface %s: clear by reset", ifp->name);
+
+ /* Reset the interface */
+ thread_add_event (master, interface_down, oi, 0);
+ thread_add_event (master, interface_up, oi, 0);
+}
+
+/* Clear interface */
+DEFUN (clear_ipv6_ospf6_interface,
+ clear_ipv6_ospf6_interface_cmd,
+ "clear ipv6 ospf6 interface [IFNAME]",
+ CLEAR_STR
+ IP6_STR
+ OSPF6_STR
+ INTERFACE_STR
+ IFNAME_STR
+ )
+{
+ struct interface *ifp;
+ struct listnode *node;
+
+ if (argc == 0) /* Clear all the ospfv3 interfaces. */
+ {
+ for (ALL_LIST_ELEMENTS_RO (iflist, node, ifp))
+ ospf6_interface_clear (vty, ifp);
+ }
+ else /* Interface name is specified. */
+ {
+ if ((ifp = if_lookup_by_name (argv[0])) == NULL)
+ {
+ vty_out (vty, "No such Interface: %s%s", argv[0], VNL);
+ return CMD_WARNING;
+ }
+ ospf6_interface_clear (vty, ifp);
+ }
+
+ return CMD_SUCCESS;
+}
+
+void
+install_element_ospf6_clear_interface (void)
+{
+ install_element (ENABLE_NODE, &clear_ipv6_ospf6_interface_cmd);
+}
+
DEFUN (debug_ospf6_interface,
debug_ospf6_interface_cmd,
"debug ospf6 interface",
diff --git a/ospf6d/ospf6_interface.h b/ospf6d/ospf6_interface.h
index 95a377fb..dde589b8 100644
--- a/ospf6d/ospf6_interface.h
+++ b/ospf6d/ospf6_interface.h
@@ -78,6 +78,9 @@ struct ospf6_interface
/* Interface State */
u_char state;
+ /* Interface socket setting trial counter, resets on success */
+ u_char sso_try_cnt;
+
/* OSPF6 Interface flag */
char flag;
@@ -140,7 +143,8 @@ extern const char *ospf6_interface_state_str[];
#define OSPF6_INTERFACE_INSTANCE_ID 0
#define OSPF6_INTERFACE_BANDWIDTH 10000 /* Kbps */
#define OSPF6_REFERENCE_BANDWIDTH 100000 /* Kbps */
-
+#define OSPF6_INTERFACE_SSO_RETRY_INT 1
+#define OSPF6_INTERFACE_SSO_RETRY_MAX 5
/* Function Prototypes */
@@ -166,6 +170,8 @@ extern int neighbor_change (struct thread *);
extern void ospf6_interface_init (void);
+extern void install_element_ospf6_clear_interface (void);
+
extern int config_write_ospf6_debug_interface (struct vty *vty);
extern void install_element_ospf6_debug_interface (void);
diff --git a/ospf6d/ospf6_intra.c b/ospf6d/ospf6_intra.c
index 6606c96d..f2cade22 100644
--- a/ospf6d/ospf6_intra.c
+++ b/ospf6d/ospf6_intra.c
@@ -140,6 +140,31 @@ ospf6_router_lsa_show (struct vty *vty, struct ospf6_lsa *lsa)
return 0;
}
+static void
+ospf6_router_lsa_options_set (struct ospf6_area *oa,
+ struct ospf6_router_lsa *router_lsa)
+{
+ OSPF6_OPT_CLEAR_ALL (router_lsa->options);
+ memcpy (router_lsa->options, oa->options, 3);
+
+ if (ospf6_is_router_abr (ospf6))
+ SET_FLAG (router_lsa->bits, OSPF6_ROUTER_BIT_B);
+ else
+ UNSET_FLAG (router_lsa->bits, OSPF6_ROUTER_BIT_B);
+
+ if (!IS_AREA_STUB (oa) && ospf6_asbr_is_asbr (oa->ospf6))
+ {
+ SET_FLAG (router_lsa->bits, OSPF6_ROUTER_BIT_E);
+ }
+ else
+ {
+ UNSET_FLAG (router_lsa->bits, OSPF6_ROUTER_BIT_E);
+ }
+
+ UNSET_FLAG (router_lsa->bits, OSPF6_ROUTER_BIT_V);
+ UNSET_FLAG (router_lsa->bits, OSPF6_ROUTER_BIT_W);
+}
+
int
ospf6_router_is_stub_router (struct ospf6_lsa *lsa)
{
@@ -194,23 +219,7 @@ ospf6_router_lsa_originate (struct thread *thread)
router_lsa = (struct ospf6_router_lsa *)
((caddr_t) lsa_header + sizeof (struct ospf6_lsa_header));
- OSPF6_OPT_SET (router_lsa->options, OSPF6_OPT_V6);
- OSPF6_OPT_SET (router_lsa->options, OSPF6_OPT_E);
- OSPF6_OPT_CLEAR (router_lsa->options, OSPF6_OPT_MC);
- OSPF6_OPT_CLEAR (router_lsa->options, OSPF6_OPT_N);
- OSPF6_OPT_SET (router_lsa->options, OSPF6_OPT_R);
- OSPF6_OPT_CLEAR (router_lsa->options, OSPF6_OPT_DC);
-
- if (ospf6_is_router_abr (ospf6))
- SET_FLAG (router_lsa->bits, OSPF6_ROUTER_BIT_B);
- else
- UNSET_FLAG (router_lsa->bits, OSPF6_ROUTER_BIT_B);
- if (ospf6_asbr_is_asbr (ospf6))
- SET_FLAG (router_lsa->bits, OSPF6_ROUTER_BIT_E);
- else
- UNSET_FLAG (router_lsa->bits, OSPF6_ROUTER_BIT_E);
- UNSET_FLAG (router_lsa->bits, OSPF6_ROUTER_BIT_V);
- UNSET_FLAG (router_lsa->bits, OSPF6_ROUTER_BIT_W);
+ ospf6_router_lsa_options_set (oa, router_lsa);
/* describe links for each interfaces */
lsdesc = (struct ospf6_router_lsdesc *)
@@ -228,7 +237,7 @@ ospf6_router_lsa_originate (struct thread *thread)
for (ALL_LIST_ELEMENTS_RO (oi->neighbor_list, j, on))
if (on->state == OSPF6_NEIGHBOR_FULL)
count++;
-
+
if (count == 0)
continue;
@@ -246,30 +255,6 @@ ospf6_router_lsa_originate (struct thread *thread)
return 0;
}
- /* Fill LSA Header */
- lsa_header->age = 0;
- lsa_header->type = htons (OSPF6_LSTYPE_ROUTER);
- lsa_header->id = htonl (link_state_id);
- lsa_header->adv_router = oa->ospf6->router_id;
- lsa_header->seqnum =
- ospf6_new_ls_seqnum (lsa_header->type, lsa_header->id,
- lsa_header->adv_router, oa->lsdb);
- lsa_header->length = htons ((caddr_t) lsdesc - (caddr_t) buffer);
-
- /* LSA checksum */
- ospf6_lsa_checksum (lsa_header);
-
- /* create LSA */
- lsa = ospf6_lsa_create (lsa_header);
-
- /* Originate */
- ospf6_lsa_originate_area (lsa, oa);
-
- /* Reset setting for consecutive origination */
- memset ((caddr_t) router_lsa + sizeof (struct ospf6_router_lsa),
- 0, (caddr_t) lsdesc - (caddr_t) router_lsa);
- lsdesc = (struct ospf6_router_lsdesc *)
- ((caddr_t) router_lsa + sizeof (struct ospf6_router_lsa));
link_state_id ++;
}
@@ -338,7 +323,7 @@ ospf6_router_lsa_originate (struct thread *thread)
lsa_header->adv_router = oa->ospf6->router_id;
lsa_header->seqnum =
ospf6_new_ls_seqnum (lsa_header->type, lsa_header->id,
- lsa_header->adv_router, oa->lsdb);
+ lsa_header->adv_router, oa->lsdb);
lsa_header->length = htons ((caddr_t) lsdesc - (caddr_t) buffer);
/* LSA checksum */
@@ -355,14 +340,25 @@ ospf6_router_lsa_originate (struct thread *thread)
/* Do premature-aging of rest, undesired Router-LSAs */
type = ntohs (OSPF6_LSTYPE_ROUTER);
router = oa->ospf6->router_id;
+ count = 0;
for (lsa = ospf6_lsdb_type_router_head (type, router, oa->lsdb); lsa;
lsa = ospf6_lsdb_type_router_next (type, router, lsa))
{
if (ntohl (lsa->header->id) < link_state_id)
continue;
ospf6_lsa_purge (lsa);
+ count++;
}
+ /*
+ * Waiting till the LSA is actually removed from the database to trigger
+ * SPF delays network convergence. Unlike IPv4, for an ABR, when all
+ * interfaces associated with an area are gone, triggering an SPF right away
+ * helps convergence with inter-area routes.
+ */
+ if (count && !link_state_id)
+ ospf6_spf_schedule (oa->ospf6, OSPF6_SPF_FLAGS_ROUTER_LSA_ORIGINATED);
+
return 0;
}
@@ -459,7 +455,15 @@ ospf6_network_lsa_originate (struct thread *thread)
if (oi->state != OSPF6_INTERFACE_DR)
{
if (old)
- ospf6_lsa_purge (old);
+ {
+ ospf6_lsa_purge (old);
+ /*
+ * Waiting till the LSA is actually removed from the database to
+ * trigger SPF delays network convergence.
+ */
+ ospf6_spf_schedule (oi->area->ospf6,
+ OSPF6_SPF_FLAGS_NETWORK_LSA_ORIGINATED);
+ }
return 0;
}
@@ -468,11 +472,11 @@ ospf6_network_lsa_originate (struct thread *thread)
/* If none of neighbor is adjacent to us */
count = 0;
-
+
for (ALL_LIST_ELEMENTS_RO (oi->neighbor_list, i, on))
if (on->state == OSPF6_NEIGHBOR_FULL)
count++;
-
+
if (count == 0)
{
if (IS_OSPF6_DEBUG_ORIGINATE (NETWORK))
@@ -1078,7 +1082,7 @@ ospf6_intra_prefix_lsa_originate_transit (struct thread *thread)
for (ALL_LIST_ELEMENTS_RO (oi->neighbor_list, i, on))
if (on->state == OSPF6_NEIGHBOR_FULL)
full_count++;
-
+
if (full_count == 0)
{
if (IS_OSPF6_DEBUG_ORIGINATE (INTRA_PREFIX))
@@ -1214,7 +1218,7 @@ ospf6_intra_prefix_lsa_add (struct ospf6_lsa *lsa)
struct ospf6_intra_prefix_lsa *intra_prefix_lsa;
struct prefix ls_prefix;
struct ospf6_route *route, *ls_entry;
- int i, prefix_num;
+ int prefix_num;
struct ospf6_prefix *op;
char *start, *current, *end;
char buf[64];
@@ -1275,14 +1279,13 @@ ospf6_intra_prefix_lsa_add (struct ospf6_lsa *lsa)
break;
/* Appendix A.4.1.1 */
- if (CHECK_FLAG(op->prefix_options, OSPF6_PREFIX_OPTION_NU) ||
- CHECK_FLAG(op->prefix_options, OSPF6_PREFIX_OPTION_LA))
+ if (CHECK_FLAG(op->prefix_options, OSPF6_PREFIX_OPTION_NU))
{
if (IS_OSPF6_DEBUG_EXAMIN (INTRA_PREFIX))
{
ospf6_linkstate_prefix2str ((struct prefix *)OSPF6_PREFIX_BODY(op),
buf, sizeof (buf));
- zlog_debug ("%s: Skipping Prefix %s has NU/LA option set",
+ zlog_debug ("%s: Skipping Prefix %s has NU option set",
__func__, buf);
}
continue;
@@ -1310,13 +1313,11 @@ ospf6_intra_prefix_lsa_add (struct ospf6_lsa *lsa)
{
ifp = if_lookup_prefix(&route->prefix);
if (ifp)
- route->nexthop[0].ifindex = ifp->ifindex;
+ ospf6_route_add_nexthop (route, ifp->ifindex, NULL);
}
else
{
- for (i = 0; ospf6_nexthop_is_set (&ls_entry->nexthop[i]) &&
- i < OSPF6_MULTI_PATH_LIMIT; i++)
- ospf6_nexthop_copy (&route->nexthop[i], &ls_entry->nexthop[i]);
+ ospf6_route_copy_nexthops (route, ls_entry);
}
if (IS_OSPF6_DEBUG_EXAMIN (INTRA_PREFIX))
@@ -1339,7 +1340,7 @@ ospf6_intra_prefix_lsa_remove (struct ospf6_lsa *lsa)
struct ospf6_area *oa;
struct ospf6_intra_prefix_lsa *intra_prefix_lsa;
struct prefix prefix;
- struct ospf6_route *route;
+ struct ospf6_route *route, *nroute;
int prefix_num;
struct ospf6_prefix *op;
char *start, *current, *end;
@@ -1377,8 +1378,9 @@ ospf6_intra_prefix_lsa_remove (struct ospf6_lsa *lsa)
for (ospf6_route_lock (route);
route && ospf6_route_is_prefix (&prefix, route);
- route = ospf6_route_next (route))
+ route = nroute)
{
+ nroute = ospf6_route_next (route);
if (route->type != OSPF6_DEST_TYPE_NETWORK)
continue;
if (route->path.area_id != oa->area_id)
@@ -1408,7 +1410,7 @@ ospf6_intra_prefix_lsa_remove (struct ospf6_lsa *lsa)
void
ospf6_intra_route_calculation (struct ospf6_area *oa)
{
- struct ospf6_route *route;
+ struct ospf6_route *route, *nroute;
u_int16_t type;
struct ospf6_lsa *lsa;
void (*hook_add) (struct ospf6_route *) = NULL;
@@ -1435,8 +1437,9 @@ ospf6_intra_route_calculation (struct ospf6_area *oa)
oa->route_table->hook_remove = hook_remove;
for (route = ospf6_route_head (oa->route_table); route;
- route = ospf6_route_next (route))
+ route = nroute)
{
+ nroute = ospf6_route_next (route);
if (CHECK_FLAG (route->flag, OSPF6_ROUTE_REMOVE) &&
CHECK_FLAG (route->flag, OSPF6_ROUTE_ADD))
{
@@ -1452,7 +1455,11 @@ ospf6_intra_route_calculation (struct ospf6_area *oa)
if (hook_add)
(*hook_add) (route);
}
-
+ else
+ {
+ /* Redo the summaries as things might have changed */
+ ospf6_abr_originate_summary (route);
+ }
route->flag = 0;
}
@@ -1510,13 +1517,13 @@ ospf6_brouter_debug_print (struct ospf6_route *brouter)
id, adv_router);
zlog_info (" options: %s router-bits: %s metric-type: %d metric: %d/%d",
options, capa, brouter->path.metric_type,
- brouter->path.cost, brouter->path.cost_e2);
+ brouter->path.cost, brouter->path.u.cost_e2);
}
void
ospf6_intra_brouter_calculation (struct ospf6_area *oa)
{
- struct ospf6_route *brouter, *copy;
+ struct ospf6_route *brouter, *nbrouter, *copy;
void (*hook_add) (struct ospf6_route *) = NULL;
void (*hook_remove) (struct ospf6_route *) = NULL;
u_int32_t brouter_id;
@@ -1538,7 +1545,7 @@ ospf6_intra_brouter_calculation (struct ospf6_area *oa)
inet_ntop (AF_INET, &brouter_id, brouter_name, sizeof (brouter_name));
if (brouter->path.area_id != oa->area_id)
continue;
- brouter->flag = OSPF6_ROUTE_REMOVE;
+ SET_FLAG (brouter->flag, OSPF6_ROUTE_REMOVE);
if (IS_OSPF6_DEBUG_BROUTER_SPECIFIC_ROUTER_ID (brouter_id) ||
IS_OSPF6_DEBUG_ROUTE (MEMORY))
@@ -1585,8 +1592,9 @@ ospf6_intra_brouter_calculation (struct ospf6_area *oa)
oa->ospf6->brouter_table->hook_remove = hook_remove;
for (brouter = ospf6_route_head (oa->ospf6->brouter_table); brouter;
- brouter = ospf6_route_next (brouter))
+ brouter = nbrouter)
{
+ nbrouter = ospf6_route_next (brouter);
brouter_id = ADV_ROUTER_IN_PREFIX (&brouter->prefix);
inet_ntop (AF_INET, &brouter_id, brouter_name, sizeof (brouter_name));
@@ -1631,9 +1639,11 @@ ospf6_intra_brouter_calculation (struct ospf6_area *oa)
IS_OSPF6_DEBUG_BROUTER_SPECIFIC_AREA_ID (oa->area_id))
zlog_info ("brouter %s still exists via area %s",
brouter_name, oa->name);
+ /* But re-originate summaries */
+ ospf6_abr_originate_summary (brouter);
}
-
- brouter->flag = 0;
+ UNSET_FLAG (brouter->flag, OSPF6_ROUTE_ADD);
+ UNSET_FLAG (brouter->flag, OSPF6_ROUTE_CHANGE);
}
if (IS_OSPF6_DEBUG_BROUTER_SPECIFIC_AREA_ID (oa->area_id))
diff --git a/ospf6d/ospf6_lsa.h b/ospf6d/ospf6_lsa.h
index a85ca66d..aa64a772 100644
--- a/ospf6d/ospf6_lsa.h
+++ b/ospf6d/ospf6_lsa.h
@@ -141,6 +141,7 @@ struct ospf6_lsa
#define OSPF6_LSA_FLOODBACK 0x02
#define OSPF6_LSA_DUPLICATE 0x04
#define OSPF6_LSA_IMPLIEDACK 0x08
+#define OSPF6_LSA_UNAPPROVED 0x10
#define OSPF6_LSA_SEQWRAPPED 0x20
struct ospf6_lsa_handler
diff --git a/ospf6d/ospf6_lsdb.c b/ospf6d/ospf6_lsdb.c
index b5a4587c..d103d23f 100644
--- a/ospf6d/ospf6_lsdb.c
+++ b/ospf6d/ospf6_lsdb.c
@@ -31,7 +31,9 @@
#include "ospf6_proto.h"
#include "ospf6_lsa.h"
#include "ospf6_lsdb.h"
+#include "ospf6_route.h"
#include "ospf6d.h"
+#include "bitfield.h"
struct ospf6_lsdb *
ospf6_lsdb_create (void *data)
@@ -545,21 +547,42 @@ ospf6_lsdb_show (struct vty *vty, enum ospf_lsdb_show_level level,
}
}
-/* Decide new Link State ID to originate.
- note return value is network byte order */
+/* Decide new Link State ID to originate for the range. */
+u_int32_t
+ospf6_new_range_ls_id (struct ospf6_route_table *range_table)
+{
+ u_int32_t id;
+
+ bf_assign_index(range_table->idspace, id);
+ return (id);
+}
+
+/* Release the LS ID back to the ID pool */
+void
+ospf6_release_range_ls_id (struct ospf6_route_table *range_table,
+ u_int32_t id)
+{
+ bf_release_index(range_table->idspace, id);
+}
+
u_int32_t
ospf6_new_ls_id (u_int16_t type, u_int32_t adv_router,
struct ospf6_lsdb *lsdb)
{
struct ospf6_lsa *lsa;
- u_int32_t id = 1;
+ u_int32_t id = 1, tmp_id;
+ /* This routine is curently invoked only for Inter-Prefix LSAs for
+ * non-summarized routes (no area/range).
+ */
for (lsa = ospf6_lsdb_type_router_head (type, adv_router, lsdb); lsa;
lsa = ospf6_lsdb_type_router_next (type, adv_router, lsa))
{
- if (ntohl (lsa->header->id) < id)
- continue;
- if (ntohl (lsa->header->id) > id)
+ tmp_id = ntohl (lsa->header->id);
+ if (tmp_id < id)
+ continue;
+
+ if (tmp_id > id)
{
ospf6_lsdb_lsa_unlock (lsa);
break;
diff --git a/ospf6d/ospf6_lsdb.h b/ospf6d/ospf6_lsdb.h
index 425f6153..a8bfcae8 100644
--- a/ospf6d/ospf6_lsdb.h
+++ b/ospf6d/ospf6_lsdb.h
@@ -24,6 +24,7 @@
#include "prefix.h"
#include "table.h"
+#include "ospf6_route.h"
struct ospf6_lsdb
{
@@ -80,6 +81,9 @@ extern void ospf6_lsdb_show (struct vty *vty,
extern u_int32_t ospf6_new_ls_id (u_int16_t type, u_int32_t adv_router,
struct ospf6_lsdb *lsdb);
+extern u_int32_t ospf6_new_range_ls_id (struct ospf6_route_table *range_table);
+extern void ospf6_release_range_ls_id (struct ospf6_route_table *range_table,
+ u_int32_t id);
extern u_int32_t ospf6_new_ls_seqnum (u_int16_t type, u_int32_t id,
u_int32_t adv_router,
struct ospf6_lsdb *lsdb);
diff --git a/ospf6d/ospf6_main.c b/ospf6d/ospf6_main.c
index 1afe84a7..11cd195f 100644
--- a/ospf6d/ospf6_main.c
+++ b/ospf6d/ospf6_main.c
@@ -21,6 +21,7 @@
#include <zebra.h>
#include <lib/version.h>
+#include <stdlib.h>
#include "getopt.h"
#include "thread.h"
@@ -238,6 +239,9 @@ main (int argc, char *argv[], char *envp[])
/* Preserve name of myself. */
progname = ((p = strrchr (argv[0], '/')) ? ++p : argv[0]);
+ /* Seed random number for LSA ID */
+ srand (time(NULL));
+
/* Command line argument treatment. */
while (1)
{
diff --git a/ospf6d/ospf6_message.c b/ospf6d/ospf6_message.c
index d382f038..b0e94288 100644
--- a/ospf6d/ospf6_message.c
+++ b/ospf6d/ospf6_message.c
@@ -245,6 +245,7 @@ ospf6_hello_recv (struct in6_addr *src, struct in6_addr *dst,
char *p;
int twoway = 0;
int neighborchange = 0;
+ int neighbor_ifindex_change = 0;
int backupseen = 0;
hello = (struct ospf6_hello *)
@@ -285,10 +286,16 @@ ospf6_hello_recv (struct in6_addr *src, struct in6_addr *dst,
on->priority = hello->priority;
}
- /* always override neighbor's source address and ifindex */
- on->ifindex = ntohl (hello->interface_id);
+ /* Always override neighbor's source address */
memcpy (&on->linklocal_addr, src, sizeof (struct in6_addr));
+ /* Neighbor ifindex check */
+ if (on->ifindex != (ifindex_t)ntohl (hello->interface_id))
+ {
+ on->ifindex = ntohl (hello->interface_id);
+ neighbor_ifindex_change++;
+ }
+
/* TwoWay check */
for (p = (char *) ((caddr_t) hello + sizeof (struct ospf6_hello));
p + sizeof (u_int32_t) <= OSPF6_MESSAGE_END (oh);
@@ -348,6 +355,9 @@ ospf6_hello_recv (struct in6_addr *src, struct in6_addr *dst,
thread_add_event (master, backup_seen, oi, 0);
if (neighborchange)
thread_add_event (master, neighbor_change, oi, 0);
+
+ if (neighbor_ifindex_change && on->state == OSPF6_NEIGHBOR_FULL)
+ OSPF6_ROUTER_LSA_SCHEDULE (oi->area);
}
static void
diff --git a/ospf6d/ospf6_network.c b/ospf6d/ospf6_network.c
index a7737502..53d6c359 100644
--- a/ospf6d/ospf6_network.c
+++ b/ospf6d/ospf6_network.c
@@ -112,7 +112,7 @@ ospf6_serv_sock (void)
}
/* ospf6 set socket option */
-void
+int
ospf6_sso (ifindex_t ifindex, struct in6_addr *group, int option)
{
struct ipv6_mreq mreq6;
@@ -125,8 +125,12 @@ ospf6_sso (ifindex_t ifindex, struct in6_addr *group, int option)
ret = setsockopt (ospf6_sock, IPPROTO_IPV6, option,
&mreq6, sizeof (mreq6));
if (ret < 0)
- zlog_err ("Network: setsockopt (%d) on ifindex %d failed: %s",
- option, ifindex, safe_strerror (errno));
+ {
+ zlog_err ("Network: setsockopt (%d) on ifindex %d failed: %s",
+ option, ifindex, safe_strerror (errno));
+ }
+
+ return ret;
}
static int
diff --git a/ospf6d/ospf6_network.h b/ospf6d/ospf6_network.h
index f4b74faa..4fa28395 100644
--- a/ospf6d/ospf6_network.h
+++ b/ospf6d/ospf6_network.h
@@ -29,7 +29,7 @@ extern struct in6_addr allspfrouters6;
extern struct in6_addr alldrouters6;
extern int ospf6_serv_sock (void);
-extern void ospf6_sso (ifindex_t ifindex, struct in6_addr *group, int option);
+extern int ospf6_sso (ifindex_t ifindex, struct in6_addr *group, int option);
extern int ospf6_sendmsg (struct in6_addr *, struct in6_addr *,
ifindex_t *, struct iovec *);
diff --git a/ospf6d/ospf6_route.c b/ospf6d/ospf6_route.c
index 50575564..e53ff365 100644
--- a/ospf6d/ospf6_route.c
+++ b/ospf6d/ospf6_route.c
@@ -37,6 +37,7 @@
#include "ospf6_area.h"
#include "ospf6_interface.h"
#include "ospf6d.h"
+#include "ospf6_zebra.h"
unsigned char conf_debug_ospf6_route = 0;
@@ -173,18 +174,232 @@ const char *ospf6_path_type_substr[OSPF6_PATH_TYPE_MAX] =
{ "??", "IA", "IE", "E1", "E2", };
+struct ospf6_nexthop *
+ospf6_nexthop_create (void)
+{
+ struct ospf6_nexthop *nh;
+
+ nh = XCALLOC (MTYPE_OSPF6_NEXTHOP, sizeof (struct ospf6_nexthop));
+ return nh;
+}
+
+void
+ospf6_nexthop_delete (struct ospf6_nexthop *nh)
+{
+ if (nh)
+ XFREE (MTYPE_OSPF6_NEXTHOP, nh);
+}
+
+void
+ospf6_free_nexthops (struct list *nh_list)
+{
+ struct ospf6_nexthop *nh;
+ struct listnode *node, *nnode;
+
+ if (nh_list)
+ {
+ for (ALL_LIST_ELEMENTS (nh_list, node, nnode, nh))
+ ospf6_nexthop_delete (nh);
+ }
+}
+
+void
+ospf6_clear_nexthops (struct list *nh_list)
+{
+ struct listnode *node;
+ struct ospf6_nexthop *nh;
+
+ if (nh_list)
+ {
+ for (ALL_LIST_ELEMENTS_RO (nh_list, node, nh))
+ ospf6_nexthop_clear (nh);
+ }
+}
+
+static struct ospf6_nexthop *
+ospf6_route_find_nexthop (struct list *nh_list, struct ospf6_nexthop *nh_match)
+{
+ struct listnode *node;
+ struct ospf6_nexthop *nh;
+
+ if (nh_list && nh_match)
+ {
+ for (ALL_LIST_ELEMENTS_RO (nh_list, node, nh))
+ {
+ if (ospf6_nexthop_is_same (nh, nh_match))
+ return (nh);
+ }
+ }
+
+ return (NULL);
+}
+
+void
+ospf6_copy_nexthops (struct list *dst, struct list *src)
+{
+ struct ospf6_nexthop *nh_new, *nh;
+ struct listnode *node;
+
+ if (dst && src)
+ {
+ for (ALL_LIST_ELEMENTS_RO (src, node, nh))
+ {
+ if (ospf6_nexthop_is_set (nh))
+ {
+ nh_new = ospf6_nexthop_create ();
+ ospf6_nexthop_copy (nh_new, nh);
+ listnode_add (dst, nh_new);
+ }
+ }
+ }
+}
+
+void
+ospf6_merge_nexthops (struct list *dst, struct list *src)
+{
+ struct listnode *node;
+ struct ospf6_nexthop *nh, *nh_new;
+
+ if (src && dst)
+ {
+ for (ALL_LIST_ELEMENTS_RO (src, node, nh))
+ {
+ if (!ospf6_route_find_nexthop (dst, nh))
+ {
+ nh_new = ospf6_nexthop_create ();
+ ospf6_nexthop_copy (nh_new, nh);
+ listnode_add (dst, nh_new);
+ }
+ }
+ }
+}
+
+int
+ospf6_route_cmp_nexthops (struct ospf6_route *a, struct ospf6_route *b)
+{
+ struct listnode *anode, *bnode;
+ struct ospf6_nexthop *anh, *bnh;
+
+ if (a && b)
+ {
+ if (listcount(a->nh_list) == listcount(b->nh_list))
+ {
+ for (ALL_LIST_ELEMENTS_RO (a->nh_list, anode, anh))
+ {
+ for (ALL_LIST_ELEMENTS_RO (b->nh_list, bnode, bnh))
+ if (!ospf6_nexthop_is_same (anh, bnh))
+ return (1);
+ }
+ return (0);
+ }
+ else
+ return (1);
+ }
+ /* One of the routes doesn't exist ? */
+ return (1);
+}
+
+int
+ospf6_num_nexthops (struct list *nh_list)
+{
+ return (listcount(nh_list));
+}
+
+void
+ospf6_add_nexthop (struct list *nh_list, int ifindex,
+ struct in6_addr *addr)
+{
+ struct ospf6_nexthop *nh;
+ struct ospf6_nexthop nh_match;
+
+ if (nh_list)
+ {
+ nh_match.ifindex = ifindex;
+ if (addr != NULL)
+ memcpy (&nh_match.address, addr, sizeof (struct in6_addr));
+ else
+ memset (&nh_match.address, 0, sizeof (struct in6_addr));
+
+ if (!ospf6_route_find_nexthop (nh_list, &nh_match))
+ {
+ nh = ospf6_nexthop_create();
+ ospf6_nexthop_copy (nh, &nh_match);
+ listnode_add (nh_list, nh);
+ }
+ }
+}
+
+void
+ospf6_route_zebra_copy_nexthops (struct ospf6_route *route,
+ ifindex_t *ifindexes,
+ struct in6_addr **nexthop_addr,
+ int entries)
+{
+ struct ospf6_nexthop *nh;
+ struct listnode *node;
+ char buf[64];
+ int i;
+
+ if (route)
+ {
+ i = 0;
+ for (ALL_LIST_ELEMENTS_RO (route->nh_list, node, nh))
+ {
+ if (IS_OSPF6_DEBUG_ZEBRA (SEND))
+ {
+ char ifname[IFNAMSIZ];
+ inet_ntop (AF_INET6, &nh->address, buf, sizeof (buf));
+ if (!if_indextoname(nh->ifindex, ifname))
+ strlcpy(ifname, "unknown", sizeof(ifname));
+ zlog_debug (" nexthop: %s%%%.*s(%d)", buf, IFNAMSIZ, ifname,
+ nh->ifindex);
+ }
+ if (i < entries)
+ {
+ nexthop_addr[i] = &nh->address;
+ ifindexes[i] = nh->ifindex;
+ i++;
+ }
+ else
+ {
+ return;
+ }
+ }
+ }
+}
+
+int
+ospf6_route_get_first_nh_index (struct ospf6_route *route)
+{
+ struct ospf6_nexthop *nh;
+
+ if (route)
+ {
+ if ((nh = (struct ospf6_nexthop *)listhead (route->nh_list)))
+ return (nh->ifindex);
+ }
+
+ return (-1);
+}
+
struct ospf6_route *
ospf6_route_create (void)
{
struct ospf6_route *route;
route = XCALLOC (MTYPE_OSPF6_ROUTE, sizeof (struct ospf6_route));
+ route->nh_list = list_new();
return route;
}
void
ospf6_route_delete (struct ospf6_route *route)
{
- XFREE (MTYPE_OSPF6_ROUTE, route);
+ if (route)
+ {
+ ospf6_free_nexthops (route->nh_list);
+ list_free (route->nh_list);
+ XFREE (MTYPE_OSPF6_ROUTE, route);
+ }
}
struct ospf6_route *
@@ -193,7 +408,15 @@ ospf6_route_copy (struct ospf6_route *route)
struct ospf6_route *new;
new = ospf6_route_create ();
- memcpy (new, route, sizeof (struct ospf6_route));
+ new->type = route->type;
+ memcpy (&new->prefix, &route->prefix, sizeof (struct prefix));
+ new->installed = route->installed;
+ new->changed = route->changed;
+ new->flag = route->flag;
+ new->route_option = route->route_option;
+ new->linkstate_id = route->linkstate_id;
+ new->path = route->path;
+ ospf6_copy_nexthops (new->nh_list, route->nh_list);
new->rnode = NULL;
new->prev = NULL;
new->next = NULL;
@@ -226,7 +449,7 @@ ospf6_route_unlock (struct ospf6_route *route)
/* Route compare function. If ra is more preferred, it returns
less than 0. If rb is more preferred returns greater than 0.
Otherwise (neither one is preferred), returns 0 */
-static int
+int
ospf6_route_cmp (struct ospf6_route *ra, struct ospf6_route *rb)
{
assert (ospf6_route_is_same (ra, rb));
@@ -246,8 +469,8 @@ ospf6_route_cmp (struct ospf6_route *ra, struct ospf6_route *rb)
if (ra->path.type == OSPF6_PATH_TYPE_EXTERNAL2)
{
- if (ra->path.cost_e2 != rb->path.cost_e2)
- return (ra->path.cost_e2 - rb->path.cost_e2);
+ if (ra->path.u.cost_e2 != rb->path.u.cost_e2)
+ return (ra->path.u.cost_e2 - rb->path.u.cost_e2);
}
else
{
@@ -620,7 +843,7 @@ ospf6_route_remove (struct ospf6_route *route,
if (node->info == route)
{
- if (route->next && ospf6_route_is_same (route->next, route))
+ if (route->next && route->next->rnode == node)
{
node->info = route->next;
SET_FLAG (route->next->flag, OSPF6_ROUTE_BEST);
@@ -795,6 +1018,8 @@ ospf6_route_show (struct vty *vty, struct ospf6_route *route)
char duration[16];
const char *ifname;
struct timeval now, res;
+ struct listnode *node;
+ struct ospf6_nexthop *nh;
quagga_gettime (QUAGGA_CLK_MONOTONIC, &now);
timersub (&now, &route->changed, &res);
@@ -810,27 +1035,26 @@ ospf6_route_show (struct vty *vty, struct ospf6_route *route)
else
prefix2str (&route->prefix, destination, sizeof (destination));
- /* nexthop */
- inet_ntop (AF_INET6, &route->nexthop[0].address, nexthop,
- sizeof (nexthop));
- ifname = ifindex2ifname (route->nexthop[0].ifindex);
-
- vty_out (vty, "%c%1s %2s %-30s %-25s %6.*s %s%s",
- (ospf6_route_is_best (route) ? '*' : ' '),
- OSPF6_DEST_TYPE_SUBSTR (route->type),
- OSPF6_PATH_TYPE_SUBSTR (route->path.type),
- destination, nexthop, IFNAMSIZ, ifname, duration, VNL);
-
- for (i = 1; ospf6_nexthop_is_set (&route->nexthop[i]) &&
- i < OSPF6_MULTI_PATH_LIMIT; i++)
+ i = 0;
+ for (ALL_LIST_ELEMENTS_RO (route->nh_list, node, nh))
{
/* nexthop */
- inet_ntop (AF_INET6, &route->nexthop[i].address, nexthop,
+ inet_ntop (AF_INET6, &nh->address, nexthop,
sizeof (nexthop));
- ifname = ifindex2ifname (route->nexthop[i].ifindex);
-
- vty_out (vty, "%c%1s %2s %-30s %-25s %6.*s %s%s",
- ' ', "", "", "", nexthop, IFNAMSIZ, ifname, "", VNL);
+ ifname = ifindex2ifname (nh->ifindex);
+
+ if (!i)
+ {
+ vty_out (vty, "%c%1s %2s %-30s %-25s %6.*s %s%s",
+ (ospf6_route_is_best (route) ? '*' : ' '),
+ OSPF6_DEST_TYPE_SUBSTR (route->type),
+ OSPF6_PATH_TYPE_SUBSTR (route->path.type),
+ destination, nexthop, IFNAMSIZ, ifname, duration, VNL);
+ i++;
+ }
+ else
+ vty_out (vty, "%c%1s %2s %-30s %-25s %6.*s %s%s",
+ ' ', "", "", "", nexthop, IFNAMSIZ, ifname, "", VNL);
}
}
@@ -842,7 +1066,8 @@ ospf6_route_show_detail (struct vty *vty, struct ospf6_route *route)
char area_id[16], id[16], adv_router[16], capa[16], options[16];
struct timeval now, res;
char duration[16];
- int i;
+ struct listnode *node;
+ struct ospf6_nexthop *nh;
quagga_gettime (QUAGGA_CLK_MONOTONIC, &now);
@@ -914,17 +1139,16 @@ ospf6_route_show_detail (struct vty *vty, struct ospf6_route *route)
vty_out (vty, "Metric Type: %d%s", route->path.metric_type,
VNL);
vty_out (vty, "Metric: %d (%d)%s",
- route->path.cost, route->path.cost_e2, VNL);
+ route->path.cost, route->path.u.cost_e2, VNL);
/* Nexthops */
vty_out (vty, "Nexthop:%s", VNL);
- for (i = 0; ospf6_nexthop_is_set (&route->nexthop[i]) &&
- i < OSPF6_MULTI_PATH_LIMIT; i++)
+ for (ALL_LIST_ELEMENTS_RO (route->nh_list, node, nh))
{
/* nexthop */
- inet_ntop (AF_INET6, &route->nexthop[i].address, nexthop,
+ inet_ntop (AF_INET6, &nh->address, nexthop,
sizeof (nexthop));
- ifname = ifindex2ifname (route->nexthop[i].ifindex);
+ ifname = ifindex2ifname (nh->ifindex);
vty_out (vty, " %s %.*s%s", nexthop, IFNAMSIZ, ifname, VNL);
}
vty_out (vty, "%s", VNL);
@@ -937,7 +1161,7 @@ ospf6_route_show_table_summary (struct vty *vty,
struct ospf6_route *route, *prev = NULL;
int i, pathtype[OSPF6_PATH_TYPE_MAX];
unsigned int number = 0;
- int nhinval = 0, ecmp = 0;
+ int nh_count =0 , nhinval = 0, ecmp = 0;
int alternative = 0, destination = 0;
for (i = 0; i < OSPF6_PATH_TYPE_MAX; i++)
@@ -950,9 +1174,10 @@ ospf6_route_show_table_summary (struct vty *vty,
destination++;
else
alternative++;
- if (! ospf6_nexthop_is_set (&route->nexthop[0]))
+ nh_count = ospf6_num_nexthops (route->nh_list);
+ if (!nh_count)
nhinval++;
- else if (ospf6_nexthop_is_set (&route->nexthop[1]))
+ else if (nh_count > 1)
ecmp++;
pathtype[route->path.type]++;
number++;
diff --git a/ospf6d/ospf6_route.h b/ospf6d/ospf6_route.h
index 2fb2c1d7..0836031b 100644
--- a/ospf6d/ospf6_route.h
+++ b/ospf6d/ospf6_route.h
@@ -96,7 +96,10 @@ struct ospf6_path
/* Cost */
u_int8_t metric_type;
u_int32_t cost;
- u_int32_t cost_e2;
+ union {
+ u_int32_t cost_e2;
+ u_int32_t cost_config;
+ } u;
};
#define OSPF6_PATH_TYPE_NONE 0
@@ -107,8 +110,13 @@ struct ospf6_path
#define OSPF6_PATH_TYPE_REDISTRIBUTE 5
#define OSPF6_PATH_TYPE_MAX 6
+#define OSPF6_PATH_SUBTYPE_DEFAULT_RT 1
+
+#define OSPF6_PATH_COST_IS_CONFIGURED(path) (path.u.cost_config != OSPF_AREA_RANGE_COST_UNSPEC)
+
#include "prefix.h"
#include "table.h"
+#include "bitfield.h"
struct ospf6_route
{
@@ -136,17 +144,18 @@ struct ospf6_route
/* flag */
u_char flag;
- /* path */
- struct ospf6_path path;
-
- /* nexthop */
- struct ospf6_nexthop nexthop[OSPF6_MULTI_PATH_LIMIT];
-
/* route option */
void *route_option;
/* link state id for advertising */
u_int32_t linkstate_id;
+
+ /* path */
+ struct ospf6_path path;
+
+ /* nexthop */
+ struct list *nh_list;
+
};
#define OSPF6_DEST_TYPE_NONE 0
@@ -164,6 +173,7 @@ struct ospf6_route
#define OSPF6_ROUTE_ACTIVE_SUMMARY 0x10
#define OSPF6_ROUTE_DO_NOT_ADVERTISE 0x20
#define OSPF6_ROUTE_WAS_REMOVED 0x40
+#define OSPF6_ROUTE_BLACKHOLE_ADDED 0x80
struct ospf6_route_table
{
@@ -176,6 +186,8 @@ struct ospf6_route_table
u_int32_t count;
+ bitfield_t idspace;
+
/* hooks */
void (*hook_add) (struct ospf6_route *);
void (*hook_change) (struct ospf6_route *);
@@ -235,8 +247,8 @@ extern const char *ospf6_path_type_substr[OSPF6_PATH_TYPE_MAX];
((ra)->type == (rb)->type && \
memcmp (&(ra)->prefix, &(rb)->prefix, sizeof (struct prefix)) == 0 && \
memcmp (&(ra)->path, &(rb)->path, sizeof (struct ospf6_path)) == 0 && \
- memcmp (&(ra)->nexthop, &(rb)->nexthop, \
- sizeof (struct ospf6_nexthop) * OSPF6_MULTI_PATH_LIMIT) == 0)
+ ospf6_route_cmp_nexthops (ra, rb) == 0)
+
#define ospf6_route_is_best(r) (CHECK_FLAG ((r)->flag, OSPF6_ROUTE_BEST))
#define ospf6_linkstate_prefix_adv_router(x) \
@@ -255,9 +267,35 @@ extern void ospf6_linkstate_prefix (u_int32_t adv_router, u_int32_t id,
extern void ospf6_linkstate_prefix2str (struct prefix *prefix, char *buf,
int size);
+extern struct ospf6_nexthop *ospf6_nexthop_create (void);
+extern void ospf6_nexthop_delete (struct ospf6_nexthop *nh);
+extern void ospf6_free_nexthops (struct list *nh_list);
+extern void ospf6_clear_nexthops (struct list *nh_list);
+extern int ospf6_num_nexthops (struct list *nh_list);
+extern void ospf6_copy_nexthops (struct list *dst, struct list *src);
+extern void ospf6_merge_nexthops (struct list *dst, struct list *src);
+extern void ospf6_add_nexthop (struct list *nh_list, int ifindex,
+ struct in6_addr *addr);
+extern int ospf6_num_nexthops (struct list *nh_list);
+extern int ospf6_route_cmp_nexthops (struct ospf6_route *a,
+ struct ospf6_route *b);
+extern void ospf6_route_zebra_copy_nexthops (struct ospf6_route *route,
+ ifindex_t *ifindices,
+ struct in6_addr **addr,
+ int entries);
+extern int ospf6_route_get_first_nh_index (struct ospf6_route *route);
+
+/* Hide abstraction of nexthop implementation in route from outsiders */
+#define ospf6_route_copy_nexthops(dst, src) ospf6_copy_nexthops(dst->nh_list, src->nh_list)
+#define ospf6_route_merge_nexthops(dst, src) ospf6_merge_nexthops(dst->nh_list, src->nh_list)
+#define ospf6_route_num_nexthops(route) ospf6_num_nexthops(route->nh_list)
+#define ospf6_route_add_nexthop(route, ifindex, addr) \
+ ospf6_add_nexthop(route->nh_list, ifindex, addr)
+
extern struct ospf6_route *ospf6_route_create (void);
extern void ospf6_route_delete (struct ospf6_route *);
extern struct ospf6_route *ospf6_route_copy (struct ospf6_route *route);
+extern int ospf6_route_cmp (struct ospf6_route *ra, struct ospf6_route *rb);
extern void ospf6_route_lock (struct ospf6_route *route);
extern void ospf6_route_unlock (struct ospf6_route *route);
diff --git a/ospf6d/ospf6_spf.c b/ospf6d/ospf6_spf.c
index 858398eb..c2cee36d 100644
--- a/ospf6d/ospf6_spf.c
+++ b/ospf6d/ospf6_spf.c
@@ -36,6 +36,8 @@
#include "ospf6_lsdb.h"
#include "ospf6_route.h"
#include "ospf6_area.h"
+#include "ospf6_proto.h"
+#include "ospf6_abr.h"
#include "ospf6_spf.h"
#include "ospf6_intra.h"
#include "ospf6_interface.h"
@@ -44,6 +46,41 @@
unsigned char conf_debug_ospf6_spf = 0;
+static void
+ospf6_spf_copy_nexthops_to_route (struct ospf6_route *rt,
+ struct ospf6_vertex *v)
+{
+ if (rt && v)
+ ospf6_copy_nexthops (rt->nh_list, v->nh_list);
+}
+
+static void
+ospf6_spf_merge_nexthops_to_route (struct ospf6_route *rt,
+ struct ospf6_vertex *v)
+{
+ if (rt && v)
+ ospf6_merge_nexthops (rt->nh_list, v->nh_list);
+}
+
+static unsigned int
+ospf6_spf_get_ifindex_from_nh (struct ospf6_vertex *v)
+{
+ struct ospf6_nexthop *nh;
+ struct listnode *node;
+
+ if (v)
+ {
+ node = listhead(v->nh_list);
+ if (node)
+ {
+ nh = listgetdata (node);
+ if (nh)
+ return (nh->ifindex);
+ }
+ }
+ return 0;
+}
+
static int
ospf6_vertex_cmp (void *a, void *b)
{
@@ -77,7 +114,6 @@ static struct ospf6_vertex *
ospf6_vertex_create (struct ospf6_lsa *lsa)
{
struct ospf6_vertex *v;
- int i;
v = (struct ospf6_vertex *)
XMALLOC (MTYPE_OSPF6_VERTEX, sizeof (struct ospf6_vertex));
@@ -97,6 +133,10 @@ ospf6_vertex_create (struct ospf6_lsa *lsa)
/* name */
ospf6_linkstate_prefix2str (&v->vertex_id, v->name, sizeof (v->name));
+ if (IS_OSPF6_DEBUG_SPF (PROCESS))
+ zlog_debug ("%s: Creating vertex %s of type %s", __func__, v->name,
+ ((ntohs (lsa->header->type) == OSPF6_LSTYPE_ROUTER) ? "Router" : "N/W"));
+
/* Associated LSA */
v->lsa = lsa;
@@ -106,8 +146,7 @@ ospf6_vertex_create (struct ospf6_lsa *lsa)
v->options[1] = *(u_char *)(OSPF6_LSA_HEADER_END (lsa->header) + 2);
v->options[2] = *(u_char *)(OSPF6_LSA_HEADER_END (lsa->header) + 3);
- for (i = 0; i < OSPF6_MULTI_PATH_LIMIT; i++)
- ospf6_nexthop_clear (&v->nexthop[i]);
+ v->nh_list = list_new();
v->parent = NULL;
v->child_list = list_new ();
@@ -235,11 +274,14 @@ ospf6_nexthop_calc (struct ospf6_vertex *w, struct ospf6_vertex *v,
char buf[64];
assert (VERTEX_IS_TYPE (ROUTER, w));
- ifindex = (VERTEX_IS_TYPE (NETWORK, v) ? v->nexthop[0].ifindex :
- /* v is the local router & the interface_id is a local ifindex */
- (ifindex_t) ROUTER_LSDESC_GET_IFID (lsdesc));
- assert (ifindex >= 0);
-
+ ifindex = (VERTEX_IS_TYPE (NETWORK, v) ? ospf6_spf_get_ifindex_from_nh (v) :
+ ROUTER_LSDESC_GET_IFID (lsdesc));
+ if (ifindex == 0)
+ {
+ zlog_err ("No nexthop ifindex at vertex %s", v->name);
+ return;
+ }
+
oi = ospf6_interface_lookup_by_ifindex (ifindex);
if (oi == NULL)
{
@@ -268,13 +310,8 @@ ospf6_nexthop_calc (struct ospf6_vertex *w, struct ospf6_vertex *v,
zlog_debug (" nexthop %s from %s", buf, lsa->name);
}
- if (i < OSPF6_MULTI_PATH_LIMIT)
- {
- memcpy (&w->nexthop[i].address, &link_lsa->linklocal_addr,
- sizeof (struct in6_addr));
- w->nexthop[i].ifindex = ifindex;
- i++;
- }
+ ospf6_add_nexthop (w->nh_list, ifindex, &link_lsa->linklocal_addr);
+ i++;
}
if (i == 0 && IS_OSPF6_DEBUG_SPF (PROCESS))
@@ -285,8 +322,7 @@ static int
ospf6_spf_install (struct ospf6_vertex *v,
struct ospf6_route_table *result_table)
{
- struct ospf6_route *route;
- int i, j;
+ struct ospf6_route *route, *parent_route;
struct ospf6_vertex *prev;
if (IS_OSPF6_DEBUG_SPF (PROCESS))
@@ -307,23 +343,7 @@ ospf6_spf_install (struct ospf6_vertex *v,
if (IS_OSPF6_DEBUG_SPF (PROCESS))
zlog_debug (" another path found, merge");
- for (i = 0; ospf6_nexthop_is_set (&v->nexthop[i]) &&
- i < OSPF6_MULTI_PATH_LIMIT; i++)
- {
- for (j = 0; j < OSPF6_MULTI_PATH_LIMIT; j++)
- {
- if (ospf6_nexthop_is_set (&route->nexthop[j]))
- {
- if (ospf6_nexthop_is_same (&route->nexthop[j],
- &v->nexthop[i]))
- break;
- else
- continue;
- }
- ospf6_nexthop_copy (&route->nexthop[j], &v->nexthop[i]);
- break;
- }
- }
+ ospf6_spf_merge_nexthops_to_route (route, v);
prev = (struct ospf6_vertex *) route->route_option;
assert (prev->hops <= v->hops);
@@ -350,15 +370,35 @@ ospf6_spf_install (struct ospf6_vertex *v,
route->path.origin.adv_router = v->lsa->header->adv_router;
route->path.metric_type = 1;
route->path.cost = v->cost;
- route->path.cost_e2 = v->hops;
+ route->path.u.cost_e2 = v->hops;
route->path.router_bits = v->capability;
route->path.options[0] = v->options[0];
route->path.options[1] = v->options[1];
route->path.options[2] = v->options[2];
- for (i = 0; ospf6_nexthop_is_set (&v->nexthop[i]) &&
- i < OSPF6_MULTI_PATH_LIMIT; i++)
- ospf6_nexthop_copy (&route->nexthop[i], &v->nexthop[i]);
+ ospf6_spf_copy_nexthops_to_route (route, v);
+
+ /*
+ * The SPF logic implementation does not transfer the multipathing properties
+ * of a parent to a child node. Thus if there was a 3-way multipath to a
+ * node's parent and a single hop from the parent to the child, the logic of
+ * creating new vertices and computing next hops prevents there from being 3
+ * paths to the child node. This is primarily because the resolution of
+ * multipath is done in this routine, not in the main spf loop.
+ *
+ * The following logic addresses that problem by merging the parent's nexthop
+ * information with the child's, if the parent is not the root of the tree.
+ * This is based on the assumption that before a node's route is installed,
+ * its parent's route's nexthops have already been installed.
+ */
+ if (v->parent && v->parent->hops)
+ {
+ parent_route = ospf6_route_lookup (&v->parent->vertex_id, result_table);
+ if (parent_route)
+ {
+ ospf6_route_merge_nexthops (route, parent_route);
+ }
+ }
if (v->parent)
listnode_add_sort (v->parent->child_list, v);
@@ -371,11 +411,12 @@ ospf6_spf_install (struct ospf6_vertex *v,
void
ospf6_spf_table_finish (struct ospf6_route_table *result_table)
{
- struct ospf6_route *route;
+ struct ospf6_route *route, *nroute;
struct ospf6_vertex *v;
for (route = ospf6_route_head (result_table); route;
- route = ospf6_route_next (route))
+ route = nroute)
{
+ nroute = ospf6_route_next (route);
v = (struct ospf6_vertex *) route->route_option;
ospf6_vertex_delete (v);
ospf6_route_remove (route, result_table);
@@ -421,19 +462,24 @@ ospf6_spf_calculation (u_int32_t router_id,
{
struct pqueue *candidate_list;
struct ospf6_vertex *root, *v, *w;
- int i;
int size;
caddr_t lsdesc;
struct ospf6_lsa *lsa;
+ struct in6_addr address;
ospf6_spf_table_finish (result_table);
/* Install the calculating router itself as the root of the SPF tree */
/* construct root vertex */
lsa = ospf6_lsdb_lookup (htons (OSPF6_LSTYPE_ROUTER), htonl (0),
- router_id, oa->lsdb);
+ router_id, oa->lsdb_self);
if (lsa == NULL)
- return;
+ {
+ if (IS_OSPF6_DEBUG_SPF (PROCESS))
+ zlog_debug ("%s: No router LSA for area %s\n",
+ __func__, oa->name);
+ return;
+ }
/* initialize */
candidate_list = pqueue_create ();
@@ -443,8 +489,7 @@ ospf6_spf_calculation (u_int32_t router_id,
root->area = oa;
root->cost = 0;
root->hops = 0;
- root->nexthop[0].ifindex = 0; /* loopbak I/F is better ... */
- inet_pton (AF_INET6, "::1", &root->nexthop[0].address);
+ inet_pton (AF_INET6, "::1", &address);
/* Actually insert root to the candidate-list as the only candidate */
pqueue_enqueue (root, candidate_list);
@@ -475,6 +520,9 @@ ospf6_spf_calculation (u_int32_t router_id,
if (lsa == NULL)
continue;
+ if (OSPF6_LSA_IS_MAXAGE (lsa))
+ continue;
+
if (! ospf6_lsdesc_backlink (lsa, lsdesc, v))
continue;
@@ -494,14 +542,12 @@ ospf6_spf_calculation (u_int32_t router_id,
/* nexthop calculation */
if (w->hops == 0)
- w->nexthop[0].ifindex = ROUTER_LSDESC_GET_IFID (lsdesc);
+ ospf6_add_nexthop (w->nh_list, ROUTER_LSDESC_GET_IFID (lsdesc), NULL);
else if (w->hops == 1 && v->hops == 0)
ospf6_nexthop_calc (w, v, lsdesc);
else
{
- for (i = 0; ospf6_nexthop_is_set (&v->nexthop[i]) &&
- i < OSPF6_MULTI_PATH_LIMIT; i++)
- ospf6_nexthop_copy (&w->nexthop[i], &v->nexthop[i]);
+ ospf6_copy_nexthops (w->nh_list, v->nh_list);
}
/* add new candidate to the candidate_list */
@@ -549,7 +595,6 @@ ospf6_spf_calculation_thread (struct thread *t)
struct ospf6 *ospf6;
struct timeval start, end, runtime;
struct listnode *node;
- struct ospf6_route *route;
int areas_processed = 0;
char rbuf[32];
@@ -559,6 +604,9 @@ ospf6_spf_calculation_thread (struct thread *t)
/* execute SPF calculation */
quagga_gettime (QUAGGA_CLK_MONOTONIC, &start);
+ if (ospf6_is_router_abr (ospf6))
+ ospf6_abr_range_reset_cost (ospf6);
+
for (ALL_LIST_ELEMENTS_RO(ospf6->area_list, node, oa))
{
@@ -592,10 +640,8 @@ ospf6_spf_calculation_thread (struct thread *t)
areas_processed++;
}
- /* Redo summaries if required */
- for (route = ospf6_route_head (ospf6->route_table); route;
- route = ospf6_route_next (route))
- ospf6_abr_originate_summary(route);
+ if (ospf6_is_router_abr (ospf6))
+ ospf6_abr_defaults_to_stub (ospf6);
quagga_gettime (QUAGGA_CLK_MONOTONIC, &end);
timersub (&end, &start, &runtime);
diff --git a/ospf6d/ospf6_spf.h b/ospf6d/ospf6_spf.h
index b3481dc3..7bf525d6 100644
--- a/ospf6d/ospf6_spf.h
+++ b/ospf6d/ospf6_spf.h
@@ -60,9 +60,6 @@ struct ospf6_vertex
/* Router hops to this node */
u_char hops;
- /* nexthops to this node */
- struct ospf6_nexthop nexthop[OSPF6_MULTI_PATH_LIMIT];
-
/* capability bits */
u_char capability;
@@ -72,6 +69,9 @@ struct ospf6_vertex
/* For tree display */
struct ospf6_vertex *parent;
struct list *child_list;
+
+ /* nexthops to this node */
+ struct list *nh_list;
};
#define OSPF6_VERTEX_TYPE_ROUTER 0x01
diff --git a/ospf6d/ospf6_top.c b/ospf6d/ospf6_top.c
index 7fffba83..798a1cda 100644
--- a/ospf6d/ospf6_top.c
+++ b/ospf6d/ospf6_top.c
@@ -92,6 +92,7 @@ ospf6_top_route_hook_add (struct ospf6_route *route)
static void
ospf6_top_route_hook_remove (struct ospf6_route *route)
{
+ route->flag |= OSPF6_ROUTE_REMOVE;
ospf6_abr_originate_summary (route);
ospf6_zebra_route_update_remove (route);
}
@@ -107,6 +108,7 @@ ospf6_top_brouter_hook_add (struct ospf6_route *route)
static void
ospf6_top_brouter_hook_remove (struct ospf6_route *route)
{
+ route->flag |= OSPF6_ROUTE_REMOVE;
ospf6_abr_examin_brouter (ADV_ROUTER_IN_PREFIX (&route->prefix));
ospf6_asbr_lsentry_remove (route);
ospf6_abr_originate_summary (route);
@@ -721,6 +723,8 @@ DEFUN (show_ipv6_ospf6_route,
ROUTE_STR
)
{
+ OSPF6_CMD_CHECK_RUNNING ();
+
ospf6_route_table_show (vty, argc, argv, ospf6->route_table);
return CMD_SUCCESS;
}
@@ -752,6 +756,8 @@ DEFUN (show_ipv6_ospf6_route_match,
const char *sargv[CMD_ARGC_MAX];
int i, sargc;
+ OSPF6_CMD_CHECK_RUNNING ();
+
/* copy argv to sargv and then append "match" */
for (i = 0; i < argc; i++)
sargv[i] = argv[i];
@@ -786,6 +792,8 @@ DEFUN (show_ipv6_ospf6_route_match_detail,
sargv[sargc++] = "detail";
sargv[sargc] = NULL;
+ OSPF6_CMD_CHECK_RUNNING ();
+
ospf6_route_table_show (vty, sargc, sargv, ospf6->route_table);
return CMD_SUCCESS;
}
@@ -850,6 +858,8 @@ DEFUN (show_ipv6_ospf6_route_type_detail,
sargv[sargc++] = "detail";
sargv[sargc] = NULL;
+ OSPF6_CMD_CHECK_RUNNING ();
+
ospf6_route_table_show (vty, sargc, sargv, ospf6->route_table);
return CMD_SUCCESS;
}
diff --git a/ospf6d/ospf6_zebra.c b/ospf6d/ospf6_zebra.c
index c8f20d86..5f3b66a2 100644
--- a/ospf6d/ospf6_zebra.c
+++ b/ospf6d/ospf6_zebra.c
@@ -371,7 +371,7 @@ ospf6_zebra_route_update (int type, struct ospf6_route *request)
int nhcount;
struct in6_addr **nexthops;
ifindex_t *ifindexes;
- int i, ret = 0;
+ int ret = 0;
struct prefix_ipv6 *dest;
if (IS_OSPF6_DEBUG_ZEBRA (SEND))
@@ -417,11 +417,7 @@ ospf6_zebra_route_update (int type, struct ospf6_route *request)
return;
}
- nhcount = 0;
- for (i = 0; i < OSPF6_MULTI_PATH_LIMIT; i++)
- if (ospf6_nexthop_is_set (&request->nexthop[i]))
- nhcount++;
-
+ nhcount = ospf6_route_num_nexthops (request);
if (nhcount == 0)
{
if (IS_OSPF6_DEBUG_ZEBRA (SEND))
@@ -448,20 +444,7 @@ ospf6_zebra_route_update (int type, struct ospf6_route *request)
return;
}
- for (i = 0; i < nhcount; i++)
- {
- if (IS_OSPF6_DEBUG_ZEBRA (SEND))
- {
- const char *ifname;
- inet_ntop (AF_INET6, &request->nexthop[i].address,
- buf, sizeof (buf));
- ifname = ifindex2ifname (request->nexthop[i].ifindex);
- zlog_debug (" nexthop: %s%%%.*s(%d)", buf, IFNAMSIZ, ifname,
- request->nexthop[i].ifindex);
- }
- nexthops[i] = &request->nexthop[i].address;
- ifindexes[i] = request->nexthop[i].ifindex;
- }
+ ospf6_route_zebra_copy_nexthops (request, ifindexes, nexthops, nhcount);
api.vrf_id = VRF_DEFAULT;
api.type = ZEBRA_ROUTE_OSPF6;
@@ -476,7 +459,7 @@ ospf6_zebra_route_update (int type, struct ospf6_route *request)
api.ifindex = ifindexes;
SET_FLAG (api.message, ZAPI_MESSAGE_METRIC);
api.metric = (request->path.metric_type == 2 ?
- request->path.cost_e2 : request->path.cost);
+ request->path.u.cost_e2 : request->path.cost);
dest = (struct prefix_ipv6 *) &request->prefix;
if (type == REM)
@@ -518,6 +501,90 @@ ospf6_zebra_route_update_remove (struct ospf6_route *request)
ospf6_zebra_route_update (REM, request);
}
+void
+ospf6_zebra_add_discard (struct ospf6_route *request)
+{
+ struct zapi_ipv6 api;
+ char buf[INET6_ADDRSTRLEN];
+ struct prefix_ipv6 *dest;
+
+ if (zclient->redist[ZEBRA_ROUTE_OSPF6])
+ {
+ if (!CHECK_FLAG (request->flag, OSPF6_ROUTE_BLACKHOLE_ADDED))
+ {
+ api.type = ZEBRA_ROUTE_OSPF6;
+ api.flags = ZEBRA_FLAG_BLACKHOLE;
+ api.message = 0;
+ api.safi = SAFI_UNICAST;
+ SET_FLAG (api.message, ZAPI_MESSAGE_NEXTHOP);
+ api.nexthop_num = 0;
+ api.ifindex_num = 0;
+
+ dest = (struct prefix_ipv6 *) &request->prefix;
+
+ zapi_ipv6_route (ZEBRA_IPV6_ROUTE_ADD, zclient, dest, &api);
+
+ if (IS_OSPF6_DEBUG_ZEBRA (SEND))
+ zlog_debug ("Zebra: Route add discard %s/%d",
+ inet_ntop (AF_INET6, &dest->prefix,
+ buf, INET6_ADDRSTRLEN),
+ dest->prefixlen);
+ SET_FLAG (request->flag, OSPF6_ROUTE_BLACKHOLE_ADDED);
+ }
+ else
+ {
+ dest = (struct prefix_ipv6 *) &request->prefix;
+
+ if (IS_OSPF6_DEBUG_ZEBRA (SEND))
+ zlog_debug ("Zebra: Blackhole route present already %s/%d",
+ inet_ntop (AF_INET6, &dest->prefix,
+ buf, INET6_ADDRSTRLEN),
+ dest->prefixlen);
+ }
+ }
+}
+
+void
+ospf6_zebra_delete_discard (struct ospf6_route *request)
+{
+ struct zapi_ipv6 api;
+ char buf[INET6_ADDRSTRLEN];
+ struct prefix_ipv6 *dest;
+
+ if (zclient->redist[ZEBRA_ROUTE_OSPF6])
+ {
+ if (CHECK_FLAG (request->flag, OSPF6_ROUTE_BLACKHOLE_ADDED))
+ {
+
+ api.type = ZEBRA_ROUTE_OSPF6;
+ api.flags = ZEBRA_FLAG_BLACKHOLE;
+ api.message = 0;
+ api.safi = SAFI_UNICAST;
+ SET_FLAG (api.message, ZAPI_MESSAGE_NEXTHOP);
+ api.nexthop_num = 0;
+ api.ifindex_num = 0;
+
+ dest = (struct prefix_ipv6 *) &request->prefix;
+
+ zapi_ipv6_route (ZEBRA_IPV6_ROUTE_DELETE, zclient, dest, &api);
+
+ if (IS_OSPF6_DEBUG_ZEBRA (SEND))
+ zlog_debug ("Zebra: Route delete discard %s/%d",
+ inet_ntop (AF_INET6, &dest->prefix, buf,
+ INET6_ADDRSTRLEN), dest->prefixlen);
+ UNSET_FLAG (request->flag, OSPF6_ROUTE_BLACKHOLE_ADDED);
+ }
+ else
+ {
+ dest = (struct prefix_ipv6 *) &request->prefix;
+ if (IS_OSPF6_DEBUG_ZEBRA (SEND))
+ zlog_debug ("Zebra: Blackhole route already deleted %s/%d",
+ inet_ntop (AF_INET6, &dest->prefix, buf,
+ INET6_ADDRSTRLEN), dest->prefixlen);
+ }
+ }
+}
+
DEFUN (redistribute_ospf6,
redistribute_ospf6_cmd,
"redistribute ospf6",
diff --git a/ospf6d/ospf6_zebra.h b/ospf6d/ospf6_zebra.h
index 05694d39..4d028182 100644
--- a/ospf6d/ospf6_zebra.h
+++ b/ospf6d/ospf6_zebra.h
@@ -45,6 +45,8 @@ extern void ospf6_zebra_no_redistribute (int);
#define ospf6_zebra_is_redistribute(type) \
vrf_bitmap_check (zclient->redist[type], VRF_DEFAULT)
extern void ospf6_zebra_init(struct thread_master *);
+extern void ospf6_zebra_add_discard (struct ospf6_route *request);
+extern void ospf6_zebra_delete_discard (struct ospf6_route *request);
extern int config_write_ospf6_debug_zebra (struct vty *vty);
extern void install_element_ospf6_debug_zebra (void);
diff --git a/ospf6d/ospf6d.c b/ospf6d/ospf6d.c
index c2baa314..c929dfff 100644
--- a/ospf6d/ospf6d.c
+++ b/ospf6d/ospf6d.c
@@ -1690,6 +1690,8 @@ DEFUN (show_ipv6_ospf6_linkstate,
struct listnode *node;
struct ospf6_area *oa;
+ OSPF6_CMD_CHECK_RUNNING ();
+
for (ALL_LIST_ELEMENTS_RO (ospf6->area_list, node, oa))
{
vty_out (vty, "%s SPF Result in Area %s%s%s",
@@ -1738,6 +1740,8 @@ DEFUN (show_ipv6_ospf6_linkstate_detail,
struct listnode *node;
struct ospf6_area *oa;
+ OSPF6_CMD_CHECK_RUNNING ();
+
/* copy argv to sargv and then append "detail" */
for (i = 0; i < argc; i++)
sargv[i] = argv[i];
@@ -1790,6 +1794,8 @@ ospf6_init (void)
install_element_ospf6_debug_abr ();
install_element_ospf6_debug_flood ();
+ install_element_ospf6_clear_interface ();
+
install_element (VIEW_NODE, &show_version_ospf6_cmd);
install_element (ENABLE_NODE, &show_version_ospf6_cmd);
@@ -1892,6 +1898,8 @@ ospf6_init (void)
void
ospf6_clean (void)
{
+ if (!ospf6)
+ return;
if (ospf6->route_table)
ospf6_route_remove_all (ospf6->route_table);
if (ospf6->brouter_table)