summaryrefslogtreecommitdiff
path: root/ospf6d
diff options
context:
space:
mode:
Diffstat (limited to 'ospf6d')
-rw-r--r--ospf6d/ospf6_abr.c27
-rw-r--r--ospf6d/ospf6_area.c17
-rw-r--r--ospf6d/ospf6_asbr.c1343
-rw-r--r--ospf6d/ospf6_asbr.h76
-rw-r--r--ospf6d/ospf6_flood.c66
-rw-r--r--ospf6d/ospf6_flood.h3
-rw-r--r--ospf6d/ospf6_interface.c110
-rw-r--r--ospf6d/ospf6_interface.h1
-rw-r--r--ospf6d/ospf6_intra.c46
-rw-r--r--ospf6d/ospf6_lsa.c35
-rw-r--r--ospf6d/ospf6_lsa.h5
-rw-r--r--ospf6d/ospf6_lsdb.c23
-rw-r--r--ospf6d/ospf6_message.c59
-rw-r--r--ospf6d/ospf6_nssa.c57
-rw-r--r--ospf6d/ospf6_route.c94
-rw-r--r--ospf6d/ospf6_route.h86
-rw-r--r--ospf6d/ospf6_spf.c30
-rw-r--r--ospf6d/ospf6_top.c520
-rw-r--r--ospf6d/ospf6_top.h23
-rw-r--r--ospf6d/ospf6_zebra.c44
-rw-r--r--ospf6d/ospf6d.h4
-rw-r--r--ospf6d/subdir.am3
22 files changed, 2261 insertions, 411 deletions
diff --git a/ospf6d/ospf6_abr.c b/ospf6d/ospf6_abr.c
index f289bf26b9..69be807c13 100644
--- a/ospf6d/ospf6_abr.c
+++ b/ospf6d/ospf6_abr.c
@@ -477,11 +477,11 @@ int ospf6_abr_originate_summary_to_area(struct ospf6_route *route,
monotime(&summary->changed);
}
+ summary->prefix_options = route->prefix_options;
summary->path.router_bits = route->path.router_bits;
summary->path.options[0] = route->path.options[0];
summary->path.options[1] = route->path.options[1];
summary->path.options[2] = route->path.options[2];
- summary->path.prefix_options = route->path.prefix_options;
summary->path.area_id = area->area_id;
summary->path.type = OSPF6_PATH_TYPE_INTER;
summary->path.subtype = route->path.subtype;
@@ -514,7 +514,7 @@ int ospf6_abr_originate_summary_to_area(struct ospf6_route *route,
/* Fill Inter-Area-Prefix-LSA */
OSPF6_ABR_SUMMARY_METRIC_SET(prefix_lsa, route->path.cost);
prefix_lsa->prefix.prefix_length = route->prefix.prefixlen;
- prefix_lsa->prefix.prefix_options = route->path.prefix_options;
+ prefix_lsa->prefix.prefix_options = route->prefix_options;
/* set Prefix */
memcpy(p, &route->prefix.u.prefix6,
@@ -710,25 +710,12 @@ void ospf6_abr_defaults_to_stub(struct ospf6 *o)
struct listnode *node, *nnode;
struct ospf6_area *oa;
struct ospf6_route *def, *route;
- struct ospf6_redist *red;
int type = DEFAULT_ROUTE;
- struct prefix_ipv6 p = {};
if (!o->backbone)
return;
- red = ospf6_redist_lookup(o, type, 0);
- if (!red)
- return;
-
- p.family = AF_INET6;
- p.prefixlen = 0;
-
- route = ospf6_route_lookup((struct prefix *)&p, o->external_table);
- if (!route)
- return;
-
- def = ospf6_route_create();
+ def = ospf6_route_create(o);
def->type = OSPF6_DEST_TYPE_NETWORK;
def->prefix.family = AF_INET6;
def->prefix.prefixlen = 0;
@@ -1163,10 +1150,11 @@ void ospf6_abr_examin_summary(struct ospf6_lsa *lsa, struct ospf6_area *oa)
/* (5),(6): the path preference is handled by the sorting
in the routing table. Always install the path by substituting
old route (if any). */
- route = ospf6_route_create();
+ route = ospf6_route_create(oa->ospf6);
route->type = type;
route->prefix = prefix;
+ route->prefix_options = prefix_options;
route->path.origin.type = lsa->header->type;
route->path.origin.id = lsa->header->id;
route->path.origin.adv_router = lsa->header->adv_router;
@@ -1174,7 +1162,6 @@ void ospf6_abr_examin_summary(struct ospf6_lsa *lsa, struct ospf6_area *oa)
route->path.options[0] = options[0];
route->path.options[1] = options[1];
route->path.options[2] = options[2];
- route->path.prefix_options = prefix_options;
route->path.area_id = oa->area_id;
route->path.type = OSPF6_PATH_TYPE_INTER;
route->path.cost = abr_entry->path.cost + cost;
@@ -1250,7 +1237,9 @@ void ospf6_abr_examin_summary(struct ospf6_lsa *lsa, struct ospf6_area *oa)
listcount(old_route->nh_list));
}
} else {
- struct ospf6_route *tmp_route = ospf6_route_create();
+ struct ospf6_route *tmp_route;
+
+ tmp_route = ospf6_route_create(oa->ospf6);
ospf6_copy_nexthops(tmp_route->nh_list,
o_path->nh_list);
diff --git a/ospf6d/ospf6_area.c b/ospf6d/ospf6_area.c
index 355b8441bd..0f1f061225 100644
--- a/ospf6d/ospf6_area.c
+++ b/ospf6d/ospf6_area.c
@@ -504,7 +504,7 @@ DEFUN (area_range,
struct ospf6_area *oa;
struct prefix prefix;
struct ospf6_route *range;
- uint32_t cost = OSPF_AREA_RANGE_COST_UNSPEC;
+ uint32_t cost;
VTY_DECLVAR_CONTEXT(ospf6, ospf6);
@@ -519,23 +519,22 @@ DEFUN (area_range,
range = ospf6_route_lookup(&prefix, oa->range_table);
if (range == NULL) {
- range = ospf6_route_create();
+ range = ospf6_route_create(ospf6);
range->type = OSPF6_DEST_TYPE_RANGE;
range->prefix = prefix;
range->path.area_id = oa->area_id;
range->path.cost = OSPF_AREA_RANGE_COST_UNSPEC;
}
+ /* default settings */
+ cost = OSPF_AREA_RANGE_COST_UNSPEC;
+ UNSET_FLAG(range->flag, OSPF6_ROUTE_DO_NOT_ADVERTISE);
+
if (argc > idx_type) {
- if (strmatch(argv[idx_type]->text, "not-advertise")) {
+ if (strmatch(argv[idx_type]->text, "not-advertise"))
SET_FLAG(range->flag, OSPF6_ROUTE_DO_NOT_ADVERTISE);
- } else if (strmatch(argv[idx_type]->text, "advertise")) {
- UNSET_FLAG(range->flag, OSPF6_ROUTE_DO_NOT_ADVERTISE);
- cost = range->path.u.cost_config;
- } else {
+ else if (strmatch(argv[idx_type]->text, "cost"))
cost = strtoul(argv[5]->arg, NULL, 10);
- UNSET_FLAG(range->flag, OSPF6_ROUTE_DO_NOT_ADVERTISE);
- }
}
range->path.u.cost_config = cost;
diff --git a/ospf6d/ospf6_asbr.c b/ospf6d/ospf6_asbr.c
index d7307fe375..165e409eed 100644
--- a/ospf6d/ospf6_asbr.c
+++ b/ospf6d/ospf6_asbr.c
@@ -57,6 +57,7 @@
DEFINE_MTYPE_STATIC(OSPF6D, OSPF6_EXTERNAL_INFO, "OSPF6 ext. info");
DEFINE_MTYPE_STATIC(OSPF6D, OSPF6_DIST_ARGS, "OSPF6 Distribute arguments");
DEFINE_MTYPE_STATIC(OSPF6D, OSPF6_REDISTRIBUTE, "OSPF6 Redistribute arguments");
+DEFINE_MTYPE_STATIC(OSPF6D, OSPF6_EXTERNAL_RT_AGGR, "OSPF6 ASBR Summarisation");
static void ospf6_asbr_redistribute_set(struct ospf6 *ospf6, int type);
static void ospf6_asbr_redistribute_unset(struct ospf6 *ospf6,
@@ -70,9 +71,28 @@ unsigned char conf_debug_ospf6_asbr = 0;
#define ZROUTE_NAME(x) zebra_route_string(x)
+/* Originate Type-5 and Type-7 LSA */
+static struct ospf6_lsa *ospf6_originate_type5_type7_lsas(
+ struct ospf6_route *route,
+ struct ospf6 *ospf6)
+{
+ struct ospf6_lsa *lsa;
+ struct listnode *lnode;
+ struct ospf6_area *oa = NULL;
+
+ lsa = ospf6_as_external_lsa_originate(route, ospf6);
+
+ for (ALL_LIST_ELEMENTS_RO(ospf6->area_list, lnode, oa)) {
+ if (IS_AREA_NSSA(oa))
+ ospf6_nssa_lsa_originate(route, oa);
+ }
+
+ return lsa;
+}
+
/* AS External LSA origination */
-void ospf6_as_external_lsa_originate(struct ospf6_route *route,
- struct ospf6 *ospf6)
+struct ospf6_lsa *ospf6_as_external_lsa_originate(struct ospf6_route *route,
+ struct ospf6 *ospf6)
{
char buffer[OSPF6_MAX_LSASIZE];
struct ospf6_lsa_header *lsa_header;
@@ -121,7 +141,7 @@ void ospf6_as_external_lsa_originate(struct ospf6_route *route,
as_external_lsa->prefix.prefix_length = route->prefix.prefixlen;
/* PrefixOptions */
- as_external_lsa->prefix.prefix_options = route->path.prefix_options;
+ as_external_lsa->prefix.prefix_options = route->prefix_options;
/* don't use refer LS-type */
as_external_lsa->prefix.prefix_refer_lstype = htons(0);
@@ -164,6 +184,8 @@ void ospf6_as_external_lsa_originate(struct ospf6_route *route,
/* Originate */
ospf6_lsa_originate_process(lsa, ospf6);
+
+ return lsa;
}
int ospf6_orig_as_external_lsa(struct thread *thread)
@@ -556,7 +578,7 @@ void ospf6_asbr_lsa_add(struct ospf6_lsa *lsa)
+ OSPF6_PREFIX_SPACE(external->prefix.prefix_length);
memset(&fwd_addr, 0, sizeof(struct prefix));
fwd_addr.family = AF_INET6;
- fwd_addr.prefixlen = IPV6_MAX_PREFIXLEN;
+ fwd_addr.prefixlen = IPV6_MAX_BITLEN;
memcpy(&fwd_addr.u.prefix6, (caddr_t)external + offset,
sizeof(struct in6_addr));
@@ -583,18 +605,18 @@ void ospf6_asbr_lsa_add(struct ospf6_lsa *lsa)
}
}
- route = ospf6_route_create();
+ route = ospf6_route_create(ospf6);
route->type = OSPF6_DEST_TYPE_NETWORK;
route->prefix.family = AF_INET6;
route->prefix.prefixlen = external->prefix.prefix_length;
ospf6_prefix_in6_addr(&route->prefix.u.prefix6, external,
&external->prefix);
+ route->prefix_options = external->prefix.prefix_options;
route->path.area_id = asbr_entry->path.area_id;
route->path.origin.type = lsa->header->type;
route->path.origin.id = lsa->header->id;
route->path.origin.adv_router = lsa->header->adv_router;
- route->path.prefix_options = external->prefix.prefix_options;
memcpy(&route->path.ls_prefix, &asbr_id, sizeof(struct prefix));
if (CHECK_FLAG(external->bits_metric, OSPF6_ASBR_BIT_E)) {
@@ -690,7 +712,7 @@ void ospf6_asbr_lsa_remove(struct ospf6_lsa *lsa,
if (ospf6_check_and_set_router_abr(ospf6))
oa = ospf6->backbone;
else
- oa = listgetdata(listhead(ospf6->area_list));
+ oa = listnode_head(ospf6->area_list);
}
if (oa == NULL) {
@@ -705,7 +727,7 @@ void ospf6_asbr_lsa_remove(struct ospf6_lsa *lsa,
return;
}
- route_to_del = ospf6_route_create();
+ route_to_del = ospf6_route_create(ospf6);
route_to_del->type = OSPF6_DEST_TYPE_NETWORK;
route_to_del->prefix.family = AF_INET6;
route_to_del->prefix.prefixlen = external->prefix.prefix_length;
@@ -1010,53 +1032,55 @@ static void ospf6_asbr_routemap_unset(struct ospf6_redist *red)
static int ospf6_asbr_routemap_update_timer(struct thread *thread)
{
- void **arg;
- int arg_type;
- struct ospf6 *ospf6;
+ struct ospf6 *ospf6 = THREAD_ARG(thread);
struct ospf6_redist *red;
-
- arg = THREAD_ARG(thread);
- ospf6 = (struct ospf6 *)arg[0];
- arg_type = (int)(intptr_t)arg[1];
+ int type;
ospf6->t_distribute_update = NULL;
- red = ospf6_redist_lookup(ospf6, arg_type, 0);
+ for (type = 0; type < ZEBRA_ROUTE_MAX; type++) {
+ red = ospf6_redist_lookup(ospf6, type, 0);
- if (red && ROUTEMAP_NAME(red))
- ROUTEMAP(red) = route_map_lookup_by_name(ROUTEMAP_NAME(red));
- if (red && ROUTEMAP(red)) {
- if (IS_OSPF6_DEBUG_ASBR)
- zlog_debug("%s: route-map %s update, reset redist %s",
- __func__, ROUTEMAP_NAME(red),
- ZROUTE_NAME(arg_type));
+ if (!red)
+ continue;
+
+ if (!CHECK_FLAG(red->flag, OSPF6_IS_RMAP_CHANGED))
+ continue;
+
+ if (ROUTEMAP_NAME(red))
+ ROUTEMAP(red) =
+ route_map_lookup_by_name(ROUTEMAP_NAME(red));
+
+ if (ROUTEMAP(red)) {
+ if (IS_OSPF6_DEBUG_ASBR)
+ zlog_debug(
+ "%s: route-map %s update, reset redist %s",
+ __func__, ROUTEMAP_NAME(red),
+ ZROUTE_NAME(type));
+
+ ospf6_zebra_no_redistribute(type, ospf6->vrf_id);
+ ospf6_zebra_redistribute(type, ospf6->vrf_id);
+ }
- ospf6_zebra_no_redistribute(arg_type, ospf6->vrf_id);
- ospf6_zebra_redistribute(arg_type, ospf6->vrf_id);
+ UNSET_FLAG(red->flag, OSPF6_IS_RMAP_CHANGED);
}
- XFREE(MTYPE_OSPF6_DIST_ARGS, arg);
return 0;
}
-void ospf6_asbr_distribute_list_update(int type, struct ospf6 *ospf6)
+void ospf6_asbr_distribute_list_update(struct ospf6 *ospf6,
+ struct ospf6_redist *red)
{
- void **args = NULL;
+ SET_FLAG(red->flag, OSPF6_IS_RMAP_CHANGED);
if (ospf6->t_distribute_update)
return;
- args = XCALLOC(MTYPE_OSPF6_DIST_ARGS, sizeof(void *) * 2);
-
- args[0] = ospf6;
- args[1] = (void *)((ptrdiff_t)type);
-
if (IS_OSPF6_DEBUG_ASBR)
- zlog_debug("%s: trigger redistribute %s reset thread", __func__,
- ZROUTE_NAME(type));
+ zlog_debug("%s: trigger redistribute reset thread", __func__);
ospf6->t_distribute_update = NULL;
- thread_add_timer_msec(master, ospf6_asbr_routemap_update_timer, args,
+ thread_add_timer_msec(master, ospf6_asbr_routemap_update_timer, ospf6,
OSPF_MIN_LS_INTERVAL,
&ospf6->t_distribute_update);
}
@@ -1092,8 +1116,7 @@ void ospf6_asbr_routemap_update(const char *mapname)
type));
route_map_counter_increment(ROUTEMAP(red));
-
- ospf6_asbr_distribute_list_update(type, ospf6);
+ ospf6_asbr_distribute_list_update(ospf6, red);
} else {
/*
* if the mapname matches a
@@ -1131,7 +1154,7 @@ static void ospf6_asbr_routemap_event(const char *name)
red = ospf6_redist_lookup(ospf6, type, 0);
if (red && ROUTEMAP_NAME(red)
&& (strcmp(ROUTEMAP_NAME(red), name) == 0))
- ospf6_asbr_distribute_list_update(type, ospf6);
+ ospf6_asbr_distribute_list_update(ospf6, red);
}
}
}
@@ -1300,6 +1323,28 @@ void ospf6_asbr_remove_externals_from_area(struct ospf6_area *oa)
}
}
+static struct ospf6_external_aggr_rt *
+ospf6_external_aggr_match(struct ospf6 *ospf6, struct prefix *p)
+{
+ struct route_node *node;
+
+ node = route_node_match(ospf6->rt_aggr_tbl, p);
+ if (node == NULL)
+ return NULL;
+
+ if (IS_OSPF6_DEBUG_AGGR) {
+ struct ospf6_external_aggr_rt *ag = node->info;
+ zlog_debug("%s: Matching aggregator found.prefix: %pFX Aggregator %pFX",
+ __func__,
+ p,
+ &ag->p);
+ }
+
+ route_unlock_node(node);
+
+ return node->info;
+}
+
void ospf6_asbr_redistribute_add(int type, ifindex_t ifindex,
struct prefix *prefix,
unsigned int nexthop_num,
@@ -1307,8 +1352,6 @@ void ospf6_asbr_redistribute_add(int type, ifindex_t ifindex,
struct ospf6 *ospf6)
{
route_map_result_t ret;
- struct listnode *lnode;
- struct ospf6_area *oa;
struct ospf6_route troute;
struct ospf6_external_info tinfo;
struct ospf6_route *route, *match;
@@ -1377,6 +1420,7 @@ void ospf6_asbr_redistribute_add(int type, ifindex_t ifindex,
match->path.cost = troute.path.cost;
else
match->path.cost = metric_value(ospf6, type, 0);
+
if (!IN6_IS_ADDR_UNSPECIFIED(&tinfo.forwarding))
memcpy(&info->forwarding, &tinfo.forwarding,
sizeof(struct in6_addr));
@@ -1399,7 +1443,7 @@ void ospf6_asbr_redistribute_add(int type, ifindex_t ifindex,
/* create/update binding in external_id_table */
prefix_id.family = AF_INET;
- prefix_id.prefixlen = 32;
+ prefix_id.prefixlen = IPV4_MAX_BITLEN;
prefix_id.u.prefix4.s_addr = htonl(info->id);
node = route_node_get(ospf6->external_id_table, &prefix_id);
node->info = match;
@@ -1413,25 +1457,22 @@ void ospf6_asbr_redistribute_add(int type, ifindex_t ifindex,
}
match->path.origin.id = htonl(info->id);
- ospf6_as_external_lsa_originate(match, ospf6);
+ ospf6_handle_external_lsa_origination(ospf6, match, prefix);
+
ospf6_asbr_status_update(ospf6, ospf6->redistribute);
- for (ALL_LIST_ELEMENTS_RO(ospf6->area_list, lnode, oa)) {
- if (IS_AREA_NSSA(oa))
- ospf6_nssa_lsa_originate(match, oa);
- }
return;
}
/* create new entry */
- route = ospf6_route_create();
+ route = ospf6_route_create(ospf6);
route->type = OSPF6_DEST_TYPE_NETWORK;
prefix_copy(&route->prefix, prefix);
+ route->ospf6 = ospf6;
info = (struct ospf6_external_info *)XCALLOC(
MTYPE_OSPF6_EXTERNAL_INFO, sizeof(struct ospf6_external_info));
route->route_option = info;
- info->id = ospf6->external_id++;
/* copy result of route-map */
if (ROUTEMAP(red)) {
@@ -1462,43 +1503,109 @@ void ospf6_asbr_redistribute_add(int type, ifindex_t ifindex,
else
ospf6_route_add_nexthop(route, ifindex, NULL);
- /* create/update binding in external_id_table */
- prefix_id.family = AF_INET;
- prefix_id.prefixlen = 32;
- prefix_id.u.prefix4.s_addr = htonl(info->id);
- node = route_node_get(ospf6->external_id_table, &prefix_id);
- node->info = route;
-
route = ospf6_route_add(route, ospf6->external_table);
- route->route_option = info;
+ ospf6_handle_external_lsa_origination(ospf6, route, prefix);
- if (IS_OSPF6_DEBUG_ASBR) {
- inet_ntop(AF_INET, &prefix_id.u.prefix4, ibuf, sizeof(ibuf));
- zlog_debug(
- "Advertise as AS-External Id:%s prefix %pFX metric %u",
- ibuf, prefix, route->path.metric_type);
- }
-
- route->path.origin.id = htonl(info->id);
- ospf6_as_external_lsa_originate(route, ospf6);
ospf6_asbr_status_update(ospf6, ospf6->redistribute);
+
+}
+
+static void ospf6_asbr_external_lsa_remove_by_id(struct ospf6 *ospf6,
+ uint32_t id)
+{
+ struct ospf6_lsa *lsa;
+ struct ospf6_area *oa;
+ struct listnode *lnode;
+
+ lsa = ospf6_lsdb_lookup(htons(OSPF6_LSTYPE_AS_EXTERNAL),
+ htonl(id), ospf6->router_id, ospf6->lsdb);
+ if (!lsa)
+ return;
+
+ ospf6_external_lsa_purge(ospf6, lsa);
+
+ /* Delete the NSSA LSA */
for (ALL_LIST_ELEMENTS_RO(ospf6->area_list, lnode, oa)) {
- if (IS_AREA_NSSA(oa))
- ospf6_nssa_lsa_originate(route, oa);
+ lsa = ospf6_lsdb_lookup(htons(OSPF6_LSTYPE_TYPE_7),
+ htonl(id), ospf6->router_id,
+ oa->lsdb);
+ if (lsa) {
+ if (IS_OSPF6_DEBUG_ASBR)
+ zlog_debug("withdraw type 7 lsa, LS ID: %u",
+ htonl(id));
+
+ ospf6_lsa_purge(lsa);
+ }
+ }
+
+}
+
+static void
+ospf6_link_route_to_aggr(struct ospf6_external_aggr_rt *aggr,
+ struct ospf6_route *rt)
+{
+ hash_get(aggr->match_extnl_hash, rt, hash_alloc_intern);
+ rt->aggr_route = aggr;
+}
+
+static void
+ospf6_asbr_summary_remove_lsa_and_route(struct ospf6 *ospf6,
+ struct ospf6_external_aggr_rt *aggr)
+{
+
+ /* Send a Max age LSA if it is already originated.*/
+ if (!CHECK_FLAG(aggr->aggrflags, OSPF6_EXTERNAL_AGGRT_ORIGINATED))
+ return;
+
+ if (IS_OSPF6_DEBUG_AGGR)
+ zlog_debug("%s: Flushing Aggregate route (%pFX)",
+ __func__,
+ &aggr->p);
+
+ ospf6_asbr_external_lsa_remove_by_id(ospf6, aggr->id);
+
+ if (aggr->route) {
+ if (IS_OSPF6_DEBUG_AGGR)
+ zlog_debug(
+ "%s: Remove the blackhole route",
+ __func__);
+ ospf6_zebra_route_update_remove(aggr->route, ospf6);
+ ospf6_route_delete(aggr->route);
+ aggr->route = NULL;
}
+
+ aggr->id = 0;
+ /* Unset the Origination flag */
+ UNSET_FLAG(aggr->aggrflags, OSPF6_EXTERNAL_AGGRT_ORIGINATED);
+}
+
+static void
+ospf6_unlink_route_from_aggr(struct ospf6 *ospf6,
+ struct ospf6_external_aggr_rt *aggr,
+ struct ospf6_route *rt)
+{
+ if (IS_OSPF6_DEBUG_AGGR)
+ zlog_debug("%s: Unlinking external route(%pFX) from aggregator(%pFX), external route count:%ld",
+ __func__,
+ &rt->prefix,
+ &aggr->p,
+ OSPF6_EXTERNAL_RT_COUNT(aggr));
+
+ hash_release(aggr->match_extnl_hash, rt);
+ rt->aggr_route = NULL;
+
+ /* Flush the aggregate route if matching
+ * external route count becomes zero.
+ */
+ if (!OSPF6_EXTERNAL_RT_COUNT(aggr))
+ ospf6_asbr_summary_remove_lsa_and_route(ospf6, aggr);
}
void ospf6_asbr_redistribute_remove(int type, ifindex_t ifindex,
struct prefix *prefix, struct ospf6 *ospf6)
{
- struct ospf6_area *oa;
struct ospf6_route *match;
struct ospf6_external_info *info = NULL;
- struct listnode *lnode;
- struct route_node *node;
- struct ospf6_lsa *lsa;
- struct prefix prefix_id;
- char ibuf[16];
match = ospf6_route_lookup(prefix, ospf6->external_table);
if (match == NULL) {
@@ -1516,44 +1623,17 @@ void ospf6_asbr_redistribute_remove(int type, ifindex_t ifindex,
return;
}
- if (IS_OSPF6_DEBUG_ASBR) {
- inet_ntop(AF_INET, &prefix_id.u.prefix4, ibuf, sizeof(ibuf));
- zlog_debug("Withdraw %pFX (AS-External Id:%s)", prefix, ibuf);
- }
-
- lsa = ospf6_lsdb_lookup(htons(OSPF6_LSTYPE_AS_EXTERNAL),
- htonl(info->id), ospf6->router_id, ospf6->lsdb);
- if (lsa) {
- if (IS_OSPF6_DEBUG_ASBR) {
- zlog_debug("withdraw type 5 LSA for route %pFX",
- prefix);
- }
- ospf6_lsa_purge(lsa);
- }
-
- /* Delete the NSSA LSA */
- for (ALL_LIST_ELEMENTS_RO(ospf6->area_list, lnode, oa)) {
- lsa = ospf6_lsdb_lookup(htons(OSPF6_LSTYPE_TYPE_7),
- htonl(info->id), ospf6->router_id,
- oa->lsdb);
- if (lsa) {
- if (IS_OSPF6_DEBUG_ASBR) {
- zlog_debug("withdraw type 7 LSA for route %pFX",
- prefix);
- }
- ospf6_lsa_purge(lsa);
- }
- }
+ /* This means aggregation on this route was not done, hence remove LSA
+ * if any originated for this prefix
+ */
+ if (!match->aggr_route)
+ ospf6_asbr_external_lsa_remove_by_id(ospf6, info->id);
+ else
+ ospf6_unlink_route_from_aggr(ospf6, match->aggr_route, match);
- /* remove binding in external_id_table */
- prefix_id.family = AF_INET;
- prefix_id.prefixlen = 32;
- prefix_id.u.prefix4.s_addr = htonl(info->id);
- node = route_node_lookup(ospf6->external_id_table, &prefix_id);
- assert(node);
- node->info = NULL;
- route_unlock_node(node); /* to free the lookup lock */
- route_unlock_node(node); /* to free the original lock */
+ if (IS_OSPF6_DEBUG_ASBR)
+ zlog_debug("Removing route from external table %pFX",
+ prefix);
ospf6_route_remove(match, ospf6->external_table);
XFREE(MTYPE_OSPF6_EXTERNAL_INFO, info);
@@ -1573,6 +1653,7 @@ DEFUN (ospf6_redistribute,
VTY_DECLVAR_CONTEXT(ospf6, ospf6);
char *proto = argv[argc - 1]->text;
+
type = proto_redistnum(AFI_IP6, proto);
if (type < 0)
return CMD_WARNING_CONFIG_FAILED;
@@ -2567,36 +2648,41 @@ int config_write_ospf6_debug_asbr(struct vty *vty)
return 0;
}
-int ospf6_distribute_config_write(struct vty *vty, struct ospf6 *ospf6)
+static void ospf6_default_originate_write(struct vty *vty, struct ospf6 *o)
{
struct ospf6_redist *red;
- if (ospf6) {
- /* default-route print. */
- if (ospf6->default_originate != DEFAULT_ORIGINATE_NONE) {
- vty_out(vty, " default-information originate");
- if (ospf6->default_originate
- == DEFAULT_ORIGINATE_ALWAYS)
- vty_out(vty, " always");
-
- red = ospf6_redist_lookup(ospf6, DEFAULT_ROUTE, 0);
- if (red) {
- if (red->dmetric.value >= 0)
- vty_out(vty, " metric %d",
- red->dmetric.value);
-
- if (red->dmetric.type >= 0)
- vty_out(vty, " metric-type %d",
- red->dmetric.type);
-
- if (ROUTEMAP_NAME(red))
- vty_out(vty, " route-map %s",
- ROUTEMAP_NAME(red));
- }
+ vty_out(vty, " default-information originate");
+ if (o->default_originate == DEFAULT_ORIGINATE_ALWAYS)
+ vty_out(vty, " always");
- vty_out(vty, "\n");
- }
+ red = ospf6_redist_lookup(o, DEFAULT_ROUTE, 0);
+ if (red == NULL) {
+ vty_out(vty, "\n");
+ return;
}
+
+ if (red->dmetric.value >= 0)
+ vty_out(vty, " metric %d", red->dmetric.value);
+
+ if (red->dmetric.type >= 0)
+ vty_out(vty, " metric-type %d", red->dmetric.type);
+
+ if (ROUTEMAP_NAME(red))
+ vty_out(vty, " route-map %s", ROUTEMAP_NAME(red));
+
+ vty_out(vty, "\n");
+}
+
+int ospf6_distribute_config_write(struct vty *vty, struct ospf6 *o)
+{
+ if (o == NULL)
+ return 0;
+
+ /* Print default originate configuration. */
+ if (o->default_originate != DEFAULT_ORIGINATE_NONE)
+ ospf6_default_originate_write(vty, o);
+
return 0;
}
@@ -2607,3 +2693,988 @@ void install_element_ospf6_debug_asbr(void)
install_element(CONFIG_NODE, &debug_ospf6_asbr_cmd);
install_element(CONFIG_NODE, &no_debug_ospf6_asbr_cmd);
}
+
+/* ASBR Summarisation */
+void ospf6_fill_aggr_route_details(struct ospf6 *ospf6,
+ struct ospf6_external_aggr_rt *aggr)
+{
+ struct ospf6_route *rt_aggr = aggr->route;
+ struct ospf6_external_info *ei_aggr = rt_aggr->route_option;
+
+ rt_aggr->prefix = aggr->p;
+ ei_aggr->tag = aggr->tag;
+ ei_aggr->type = 0;
+ ei_aggr->id = aggr->id;
+
+ /* When metric is not configured, apply the default metric */
+ rt_aggr->path.cost = ((aggr->metric == -1) ?
+ DEFAULT_DEFAULT_METRIC
+ : (unsigned int)(aggr->metric));
+ rt_aggr->path.metric_type = aggr->mtype;
+
+ rt_aggr->path.origin.id = htonl(aggr->id);
+}
+
+static void ospf6_originate_new_aggr_lsa(struct ospf6 *ospf6,
+ struct ospf6_external_aggr_rt *aggr)
+{
+
+ struct prefix prefix_id;
+ struct route_node *node;
+ struct ospf6_lsa *lsa = NULL;
+ struct ospf6_route *rt_aggr;
+ struct ospf6_external_info *info;
+
+ if (IS_OSPF6_DEBUG_AGGR)
+ zlog_debug("%s: Originate new aggregate route(%pFX)", __func__,
+ &aggr->p);
+
+ aggr->id = ospf6->external_id++;
+ /* create/update binding in external_id_table */
+ prefix_id.family = AF_INET;
+ prefix_id.prefixlen = 32;
+ prefix_id.u.prefix4.s_addr = htonl(aggr->id);
+ node = route_node_get(ospf6->external_id_table, &prefix_id);
+ node->info = aggr;
+
+ if (IS_OSPF6_DEBUG_AGGR)
+ zlog_debug(
+ "Advertise AS-External Id:%pI4 prefix %pFX metric %u",
+ &prefix_id.u.prefix4, &aggr->p, aggr->metric);
+
+ /* Create summary route and save it. */
+ rt_aggr = ospf6_route_create(ospf6);
+ rt_aggr->type = OSPF6_DEST_TYPE_NETWORK;
+ /* Needed to install route while calling zebra api */
+ SET_FLAG(rt_aggr->flag, OSPF6_ROUTE_BEST);
+
+ info = XCALLOC(MTYPE_OSPF6_EXTERNAL_INFO, sizeof(*info));
+ rt_aggr->route_option = info;
+ aggr->route = rt_aggr;
+
+ /* Prepare the external_info for aggregator
+ * Fill all the details which will get advertised
+ */
+ ospf6_fill_aggr_route_details(ospf6, aggr);
+
+ /* Add next-hop to Null interface. */
+ ospf6_add_route_nexthop_blackhole(rt_aggr);
+
+ ospf6_zebra_route_update_add(rt_aggr, ospf6);
+
+ /* Originate summary LSA */
+ lsa = ospf6_originate_type5_type7_lsas(rt_aggr, ospf6);
+ if (lsa) {
+ if (IS_OSPF6_DEBUG_AGGR)
+ zlog_debug("%s: Set the origination bit for aggregator",
+ __func__);
+ SET_FLAG(aggr->aggrflags, OSPF6_EXTERNAL_AGGRT_ORIGINATED);
+ }
+}
+
+static void
+ospf6_aggr_handle_advertise_change(struct ospf6 *ospf6,
+ struct ospf6_external_aggr_rt *aggr)
+{
+ /* Check if advertise option modified. */
+ if (CHECK_FLAG(aggr->aggrflags, OSPF6_EXTERNAL_AGGRT_NO_ADVERTISE)) {
+ if (IS_OSPF6_DEBUG_AGGR)
+ zlog_debug("%s: Don't originate the summary address,It is configured to not-advertise.",
+ __func__);
+ ospf6_asbr_summary_remove_lsa_and_route(ospf6, aggr);
+
+ return;
+ }
+
+ /* There are no routes present under this aggregation config, hence
+ * nothing to originate here
+ */
+ if (OSPF6_EXTERNAL_RT_COUNT(aggr) == 0) {
+ if (IS_OSPF6_DEBUG_AGGR)
+ zlog_debug("%s: No routes present under this aggregation",
+ __func__);
+ return;
+ }
+
+ if (!CHECK_FLAG(aggr->aggrflags, OSPF6_EXTERNAL_AGGRT_ORIGINATED)) {
+ if (IS_OSPF6_DEBUG_AGGR)
+ zlog_debug("%s: Now it is advertisable",
+ __func__);
+
+ ospf6_originate_new_aggr_lsa(ospf6, aggr);
+
+ return;
+ }
+}
+
+static void
+ospf6_originate_summary_lsa(struct ospf6 *ospf6,
+ struct ospf6_external_aggr_rt *aggr,
+ struct ospf6_route *rt)
+{
+ struct ospf6_lsa *lsa = NULL, *aggr_lsa = NULL;
+ struct ospf6_external_info *info = NULL;
+ struct ospf6_external_aggr_rt *old_aggr;
+ struct ospf6_as_external_lsa *external;
+ struct ospf6_route *rt_aggr = NULL;
+ route_tag_t tag = 0;
+ unsigned int metric = 0;
+ int mtype;
+
+ if (IS_OSPF6_DEBUG_AGGR)
+ zlog_debug("%s: Prepare to originate Summary route(%pFX)",
+ __func__, &aggr->p);
+
+ /* This case to handle when the overlapping aggregator address
+ * is available. Best match will be considered.So need to delink
+ * from old aggregator and link to the new aggr.
+ */
+ if (rt->aggr_route) {
+ if (rt->aggr_route != aggr) {
+ old_aggr = rt->aggr_route;
+ ospf6_unlink_route_from_aggr(ospf6, old_aggr, rt);
+ }
+ }
+
+ /* Add the external route to hash table */
+ ospf6_link_route_to_aggr(aggr, rt);
+
+ /* The key for ID field is a running number and not prefix */
+ info = rt->route_option;
+ assert(info);
+ if (info->id) {
+ lsa = ospf6_lsdb_lookup(htons(OSPF6_LSTYPE_AS_EXTERNAL),
+ htonl(info->id), ospf6->router_id,
+ ospf6->lsdb);
+ assert(lsa);
+ }
+
+ aggr_lsa = ospf6_lsdb_lookup(htons(OSPF6_LSTYPE_AS_EXTERNAL),
+ htonl(aggr->id), ospf6->router_id, ospf6->lsdb);
+
+ if (IS_OSPF6_DEBUG_AGGR)
+ zlog_debug("%s: Aggr LSA ID: %d flags %x.",
+ __func__, aggr->id, aggr->aggrflags);
+ /* Dont originate external LSA,
+ * If it is configured not to advertise.
+ */
+ if (CHECK_FLAG(aggr->aggrflags, OSPF6_EXTERNAL_AGGRT_NO_ADVERTISE)) {
+ /* If it is already originated as external LSA,
+ * But, it is configured not to advertise then
+ * flush the originated external lsa.
+ */
+ if (lsa) {
+ if (IS_OSPF6_DEBUG_AGGR)
+ zlog_debug("%s: Purge the external LSA %s.",
+ __func__, lsa->name);
+ ospf6_external_lsa_purge(ospf6, lsa);
+ info->id = 0;
+ rt->path.origin.id = 0;
+ }
+
+ if (aggr_lsa) {
+ if (IS_OSPF6_DEBUG_AGGR)
+ zlog_debug("%s: Purge the aggr external LSA %s.",
+ __func__, lsa->name);
+ ospf6_asbr_summary_remove_lsa_and_route(ospf6, aggr);
+ }
+
+ UNSET_FLAG(aggr->aggrflags, OSPF6_EXTERNAL_AGGRT_ORIGINATED);
+
+ if (IS_OSPF6_DEBUG_AGGR)
+ zlog_debug("%s: Don't originate the summary address,It is configured to not-advertise.",
+ __func__);
+ return;
+ }
+
+ /* Summary route already originated,
+ * So, Do nothing.
+ */
+ if (CHECK_FLAG(aggr->aggrflags, OSPF6_EXTERNAL_AGGRT_ORIGINATED)) {
+ if (!aggr_lsa) {
+ zlog_warn(
+ "%s: Could not refresh/originate %pFX",
+ __func__,
+ &aggr->p);
+ /* Remove the assert later */
+ assert(aggr_lsa);
+ return;
+ }
+
+ external = (struct ospf6_as_external_lsa *)OSPF6_LSA_HEADER_END
+ (aggr_lsa->header);
+ metric = (unsigned long)OSPF6_ASBR_METRIC(external);
+ tag = ospf6_as_external_lsa_get_tag(aggr_lsa);
+ mtype = CHECK_FLAG(external->bits_metric,
+ OSPF6_ASBR_BIT_E) ? 2 : 1;
+
+ /* Prepare the external_info for aggregator */
+ ospf6_fill_aggr_route_details(ospf6, aggr);
+ rt_aggr = aggr->route;
+ /* If tag/metric/metric-type modified , then re-originate the
+ * route with modified tag/metric/metric-type details.
+ */
+ if ((tag != aggr->tag)
+ || (metric != (unsigned int)rt_aggr->path.cost)
+ || (mtype != aggr->mtype)) {
+
+ if (IS_OSPF6_DEBUG_AGGR)
+ zlog_debug(
+ "%s: Routetag(old:%d new:%d)/Metric(o:%u,n:%u)/mtype(o:%d n:%d) modified,So refresh the summary route.(%pFX)",
+ __func__, tag, aggr->tag,
+ metric,
+ aggr->metric,
+ mtype, aggr->mtype,
+ &aggr->p);
+
+ aggr_lsa = ospf6_originate_type5_type7_lsas(aggr->route,
+ ospf6);
+ if (aggr_lsa)
+ SET_FLAG(aggr->aggrflags,
+ OSPF6_EXTERNAL_AGGRT_ORIGINATED);
+ }
+
+ return;
+ }
+
+ /* If the external route prefix same as aggregate route
+ * and if external route is already originated as TYPE-5
+ * then it need to be refreshed and originate bit should
+ * be set.
+ */
+ if (lsa && prefix_same(&aggr->p, &rt->prefix)) {
+ if (IS_OSPF6_DEBUG_AGGR)
+ zlog_debug("%s: External route prefix is same as aggr so refreshing LSA(%pFX)",
+ __PRETTY_FUNCTION__,
+ &aggr->p);
+
+ THREAD_OFF(lsa->refresh);
+ thread_add_event(master, ospf6_lsa_refresh, lsa, 0,
+ &lsa->refresh);
+ aggr->id = info->id;
+ SET_FLAG(aggr->aggrflags, OSPF6_EXTERNAL_AGGRT_ORIGINATED);
+ return;
+ }
+
+ ospf6_originate_new_aggr_lsa(ospf6, aggr);
+}
+
+static void ospf6_aggr_handle_external_info(void *data)
+{
+ struct ospf6_route *rt = (struct ospf6_route *)data;
+ struct ospf6_external_aggr_rt *aggr = NULL;
+ struct ospf6_lsa *lsa = NULL;
+ struct ospf6_external_info *info;
+ struct ospf6 *ospf6 = NULL;
+ struct prefix prefix_id;
+ struct route_node *node;
+
+ rt->aggr_route = NULL;
+
+ rt->to_be_processed = true;
+
+ if (IS_OSPF6_DEBUG_ASBR || IS_OSPF6_DEBUG_ORIGINATE(AS_EXTERNAL))
+ zlog_debug("%s: Handle external route for origination/refresh (%pFX)",
+ __func__,
+ &rt->prefix);
+
+ ospf6 = rt->ospf6;
+ assert(ospf6);
+
+ aggr = ospf6_external_aggr_match(ospf6,
+ &rt->prefix);
+ if (aggr) {
+ ospf6_originate_summary_lsa(ospf6, aggr, rt);
+ return;
+ }
+
+ info = rt->route_option;
+ if (info->id) {
+ lsa = ospf6_lsdb_lookup(htons(OSPF6_LSTYPE_AS_EXTERNAL),
+ htonl(info->id), ospf6->router_id,
+ ospf6->lsdb);
+ if (lsa) {
+ if (IS_OSPF6_DEBUG_AGGR)
+ zlog_debug("%s: LSA found, refresh it",
+ __func__);
+ THREAD_OFF(lsa->refresh);
+ thread_add_event(master, ospf6_lsa_refresh, lsa, 0,
+ &lsa->refresh);
+ return;
+ }
+ }
+
+ info->id = ospf6->external_id++;
+ rt->path.origin.id = htonl(info->id);
+
+ /* create/update binding in external_id_table */
+ prefix_id.family = AF_INET;
+ prefix_id.prefixlen = 32;
+ prefix_id.u.prefix4.s_addr = htonl(info->id);
+ node = route_node_get(ospf6->external_id_table, &prefix_id);
+ node->info = rt;
+
+ (void)ospf6_originate_type5_type7_lsas(rt, ospf6);
+}
+
+static void
+ospf6_asbr_summary_config_delete(struct ospf6 *ospf6, struct route_node *rn)
+{
+ struct ospf6_external_aggr_rt *aggr = rn->info;
+
+ if (IS_OSPF6_DEBUG_AGGR)
+ zlog_debug("%s: Deleting Aggregate route (%pFX)",
+ __func__,
+ &aggr->p);
+
+ ospf6_asbr_summary_remove_lsa_and_route(ospf6, aggr);
+
+ rn->info = NULL;
+ route_unlock_node(rn);
+}
+
+static int
+ospf6_handle_external_aggr_modify(struct ospf6 *ospf6,
+ struct ospf6_external_aggr_rt *aggr)
+{
+ struct ospf6_lsa *lsa = NULL;
+ struct ospf6_as_external_lsa *asel = NULL;
+ struct ospf6_route *rt_aggr;
+ unsigned int metric = 0;
+ route_tag_t tag = 0;
+ int mtype;
+
+ lsa = ospf6_lsdb_lookup(
+ htons(OSPF6_LSTYPE_AS_EXTERNAL),
+ htonl(aggr->id), ospf6->router_id,
+ ospf6->lsdb);
+ if (!lsa) {
+ zlog_warn(
+ "%s: Could not refresh/originate %pFX",
+ __func__,
+ &aggr->p);
+
+ return OSPF6_FAILURE;
+ }
+
+ asel = (struct ospf6_as_external_lsa *)
+ OSPF6_LSA_HEADER_END(lsa->header);
+ metric = (unsigned long)OSPF6_ASBR_METRIC(asel);
+ tag = ospf6_as_external_lsa_get_tag(lsa);
+ mtype = CHECK_FLAG(asel->bits_metric,
+ OSPF6_ASBR_BIT_E) ? 2 : 1;
+
+ /* Fill all the details for advertisement */
+ ospf6_fill_aggr_route_details(ospf6, aggr);
+ rt_aggr = aggr->route;
+ /* If tag/metric/metric-type modified , then
+ * re-originate the route with modified
+ * tag/metric/metric-type details.
+ */
+ if ((tag != aggr->tag)
+ || (metric
+ != (unsigned int)rt_aggr->path.cost)
+ || (mtype
+ != aggr->mtype)) {
+ if (IS_OSPF6_DEBUG_AGGR)
+ zlog_debug(
+ "%s: Changed tag(old:%d new:%d)/metric(o:%u n:%d)/mtype(o:%d n:%d),So refresh the summary route.(%pFX)",
+ __func__, tag,
+ aggr->tag,
+ metric,
+ (unsigned int)rt_aggr->path.cost,
+ mtype, aggr->mtype,
+ &aggr->p);
+
+ (void)ospf6_originate_type5_type7_lsas(
+ aggr->route,
+ ospf6);
+ }
+
+ return OSPF6_SUCCESS;
+}
+
+static void ospf6_handle_external_aggr_update(struct ospf6 *ospf6)
+{
+ struct route_node *rn = NULL;
+ int ret;
+
+ if (IS_OSPF6_DEBUG_AGGR)
+ zlog_debug("%s: Process modified aggregators.", __func__);
+
+ for (rn = route_top(ospf6->rt_aggr_tbl); rn; rn = route_next(rn)) {
+ struct ospf6_external_aggr_rt *aggr;
+
+ if (!rn->info)
+ continue;
+
+ aggr = rn->info;
+
+ if (aggr->action == OSPF6_ROUTE_AGGR_DEL) {
+ aggr->action = OSPF6_ROUTE_AGGR_NONE;
+ ospf6_asbr_summary_config_delete(ospf6, rn);
+
+ if (OSPF6_EXTERNAL_RT_COUNT(aggr))
+ hash_clean(aggr->match_extnl_hash,
+ ospf6_aggr_handle_external_info);
+
+ hash_free(aggr->match_extnl_hash);
+ XFREE(MTYPE_OSPF6_EXTERNAL_RT_AGGR, aggr);
+
+ } else if (aggr->action == OSPF6_ROUTE_AGGR_MODIFY) {
+
+ aggr->action = OSPF6_ROUTE_AGGR_NONE;
+
+ /* Check if tag/metric/metric-type modified */
+ if (CHECK_FLAG(aggr->aggrflags,
+ OSPF6_EXTERNAL_AGGRT_ORIGINATED)
+ && !CHECK_FLAG(aggr->aggrflags,
+ OSPF6_EXTERNAL_AGGRT_NO_ADVERTISE)) {
+
+ ret = ospf6_handle_external_aggr_modify(ospf6,
+ aggr);
+ if (ret == OSPF6_FAILURE)
+ continue;
+ }
+
+ /* Advertise option modified ?
+ * If so, handled it here.
+ */
+ ospf6_aggr_handle_advertise_change(ospf6, aggr);
+ }
+ }
+}
+
+static void ospf6_aggr_unlink_external_info(void *data)
+{
+ struct ospf6_route *rt = (struct ospf6_route *)data;
+
+ rt->aggr_route = NULL;
+
+ rt->to_be_processed = true;
+}
+
+void ospf6_external_aggregator_free(struct ospf6_external_aggr_rt *aggr)
+{
+ if (OSPF6_EXTERNAL_RT_COUNT(aggr))
+ hash_clean(aggr->match_extnl_hash,
+ ospf6_aggr_unlink_external_info);
+
+ if (IS_OSPF6_DEBUG_AGGR)
+ zlog_debug("%s: Release the aggregator Address(%pFX)",
+ __func__,
+ &aggr->p);
+
+ hash_free(aggr->match_extnl_hash);
+ aggr->match_extnl_hash = NULL;
+
+ XFREE(MTYPE_OSPF6_EXTERNAL_RT_AGGR, aggr);
+}
+
+static void
+ospf6_delete_all_marked_aggregators(struct ospf6 *ospf6)
+{
+ struct route_node *rn = NULL;
+ struct ospf6_external_aggr_rt *aggr;
+
+ /* Loop through all the aggregators, Delete all aggregators
+ * which are marked as DELETE. Set action to NONE for remaining
+ * aggregators
+ */
+ for (rn = route_top(ospf6->rt_aggr_tbl); rn; rn = route_next(rn)) {
+ if (!rn->info)
+ continue;
+
+ aggr = rn->info;
+
+ if (aggr->action != OSPF6_ROUTE_AGGR_DEL) {
+ aggr->action = OSPF6_ROUTE_AGGR_NONE;
+ continue;
+ }
+ ospf6_asbr_summary_config_delete(ospf6, rn);
+ ospf6_external_aggregator_free(aggr);
+ }
+}
+
+static void ospf6_handle_exnl_rt_after_aggr_del(struct ospf6 *ospf6,
+ struct ospf6_route *rt)
+{
+ struct ospf6_lsa *lsa;
+
+ /* Process only marked external routes.
+ * These routes were part of a deleted
+ * aggregator.So, originate now.
+ */
+ if (!rt->to_be_processed)
+ return;
+
+ rt->to_be_processed = false;
+
+ lsa = ospf6_find_external_lsa(ospf6, &rt->prefix);
+
+ if (lsa) {
+ THREAD_OFF(lsa->refresh);
+ thread_add_event(master, ospf6_lsa_refresh, lsa, 0,
+ &lsa->refresh);
+ } else {
+ if (IS_OSPF6_DEBUG_AGGR)
+ zlog_debug("%s: Originate external route(%pFX)",
+ __func__,
+ &rt->prefix);
+
+ (void)ospf6_originate_type5_type7_lsas(rt, ospf6);
+ }
+}
+
+static void ospf6_handle_aggregated_exnl_rt(struct ospf6 *ospf6,
+ struct ospf6_external_aggr_rt *aggr,
+ struct ospf6_route *rt)
+{
+ struct ospf6_lsa *lsa;
+ struct ospf6_as_external_lsa *ext_lsa;
+ struct ospf6_external_info *info;
+
+ /* Handling the case where the external route prefix
+ * and aggegate prefix is same
+ * If same dont flush the originated external LSA.
+ */
+ if (prefix_same(&aggr->p, &rt->prefix)) {
+ if (IS_OSPF6_DEBUG_AGGR)
+ zlog_debug("%s: External Route prefix same as Aggregator(%pFX), so dont flush.",
+ __func__,
+ &rt->prefix);
+
+ return;
+ }
+
+ info = rt->route_option;
+ assert(info);
+
+ lsa = ospf6_lsdb_lookup(htons(OSPF6_LSTYPE_AS_EXTERNAL),
+ htonl(info->id), ospf6->router_id, ospf6->lsdb);
+ if (lsa) {
+ ext_lsa = (struct ospf6_as_external_lsa
+ *)((char *)(lsa->header)
+ + sizeof(struct ospf6_lsa_header));
+
+ if (rt->prefix.prefixlen != ext_lsa->prefix.prefix_length)
+ return;
+
+ ospf6_external_lsa_purge(ospf6, lsa);
+
+ /* Resetting the ID of route */
+ rt->path.origin.id = 0;
+ info->id = 0;
+ }
+}
+
+static void
+ospf6_handle_external_aggr_add(struct ospf6 *ospf6)
+{
+ struct ospf6_route *rt = NULL;
+ struct ospf6_external_info *ei = NULL;
+ struct ospf6_external_aggr_rt *aggr;
+
+ /* Delete all the aggregators which are marked as
+ * OSPF6_ROUTE_AGGR_DEL.
+ */
+ ospf6_delete_all_marked_aggregators(ospf6);
+
+ for (rt = ospf6_route_head(ospf6->external_table); rt;
+ rt = ospf6_route_next(rt)) {
+ ei = rt->route_option;
+ if (ei == NULL)
+ continue;
+
+ if (is_default_prefix(&rt->prefix))
+ continue;
+
+ aggr = ospf6_external_aggr_match(ospf6,
+ &rt->prefix);
+
+ /* If matching aggregator found, Add
+ * the external route refrenace to the
+ * aggregator and originate the aggr
+ * route if it is advertisable.
+ * flush the external LSA if it is
+ * already originated for this external
+ * prefix.
+ */
+ if (aggr) {
+ ospf6_originate_summary_lsa(ospf6, aggr, rt);
+
+ /* All aggregated external rts
+ * are handled here.
+ */
+ ospf6_handle_aggregated_exnl_rt(
+ ospf6, aggr, rt);
+ continue;
+ }
+
+ /* External routes which are only out
+ * of aggregation will be handled here.
+ */
+ ospf6_handle_exnl_rt_after_aggr_del(
+ ospf6, rt);
+ }
+}
+
+static int ospf6_asbr_summary_process(struct thread *thread)
+{
+ struct ospf6 *ospf6 = THREAD_ARG(thread);
+ int operation = 0;
+
+ ospf6->t_external_aggr = NULL;
+ operation = ospf6->aggr_action;
+
+ if (IS_OSPF6_DEBUG_AGGR)
+ zlog_debug("%s: operation:%d",
+ __func__,
+ operation);
+
+ switch (operation) {
+ case OSPF6_ROUTE_AGGR_ADD:
+ ospf6_handle_external_aggr_add(ospf6);
+ break;
+ case OSPF6_ROUTE_AGGR_DEL:
+ case OSPF6_ROUTE_AGGR_MODIFY:
+ ospf6_handle_external_aggr_update(ospf6);
+ break;
+ default:
+ break;
+ }
+
+ return OSPF6_SUCCESS;
+}
+
+static void
+ospf6_start_asbr_summary_delay_timer(struct ospf6 *ospf6,
+ struct ospf6_external_aggr_rt *aggr,
+ ospf6_aggr_action_t operation)
+{
+ aggr->action = operation;
+
+ if (ospf6->t_external_aggr) {
+ if (ospf6->aggr_action == OSPF6_ROUTE_AGGR_ADD) {
+
+ if (IS_OSPF6_DEBUG_AGGR)
+ zlog_debug("%s: Not required to restart timer,set is already added.",
+ __func__);
+ return;
+ }
+
+ if (operation == OSPF6_ROUTE_AGGR_ADD) {
+ if (IS_OSPF6_DEBUG_AGGR)
+ zlog_debug("%s, Restarting Aggregator delay timer.",
+ __func__);
+ THREAD_OFF(ospf6->t_external_aggr);
+ }
+ }
+
+ if (IS_OSPF6_DEBUG_AGGR)
+ zlog_debug("%s: Start Aggregator delay timer %d(in seconds).",
+ __func__, ospf6->aggr_delay_interval);
+
+ ospf6->aggr_action = operation;
+ thread_add_timer(master,
+ ospf6_asbr_summary_process,
+ ospf6, ospf6->aggr_delay_interval,
+ &ospf6->t_external_aggr);
+}
+
+int ospf6_asbr_external_rt_advertise(struct ospf6 *ospf6,
+ struct prefix *p)
+{
+ struct route_node *rn;
+ struct ospf6_external_aggr_rt *aggr;
+
+ rn = route_node_lookup(ospf6->rt_aggr_tbl, p);
+ if (!rn)
+ return OSPF6_INVALID;
+
+ aggr = rn->info;
+
+ route_unlock_node(rn);
+
+ if (!CHECK_FLAG(aggr->aggrflags, OSPF6_EXTERNAL_AGGRT_NO_ADVERTISE))
+ return OSPF6_INVALID;
+
+ UNSET_FLAG(aggr->aggrflags, OSPF6_EXTERNAL_AGGRT_NO_ADVERTISE);
+
+ if (!OSPF6_EXTERNAL_RT_COUNT(aggr))
+ return OSPF6_SUCCESS;
+
+ ospf6_start_asbr_summary_delay_timer(ospf6, aggr,
+ OSPF6_ROUTE_AGGR_MODIFY);
+
+ return OSPF6_SUCCESS;
+}
+
+int ospf6_external_aggr_delay_timer_set(struct ospf6 *ospf6,
+ unsigned int interval)
+{
+ ospf6->aggr_delay_interval = interval;
+
+ return OSPF6_SUCCESS;
+}
+
+static unsigned int ospf6_external_rt_hash_key(const void *data)
+{
+ const struct ospf6_route *rt = data;
+ unsigned int key = 0;
+
+ key = prefix_hash_key(&rt->prefix);
+ return key;
+}
+
+static bool ospf6_external_rt_hash_cmp(const void *d1, const void *d2)
+{
+ const struct ospf6_route *rt1 = d1;
+ const struct ospf6_route *rt2 = d2;
+
+ return prefix_same(&rt1->prefix, &rt2->prefix);
+}
+
+static struct ospf6_external_aggr_rt *
+ospf6_external_aggr_new(struct prefix *p)
+{
+ struct ospf6_external_aggr_rt *aggr;
+
+ aggr = XCALLOC(MTYPE_OSPF6_EXTERNAL_RT_AGGR,
+ sizeof(struct ospf6_external_aggr_rt));
+
+ prefix_copy(&aggr->p, p);
+ aggr->metric = -1;
+ aggr->mtype = DEFAULT_METRIC_TYPE;
+ aggr->match_extnl_hash = hash_create(ospf6_external_rt_hash_key,
+ ospf6_external_rt_hash_cmp,
+ "Ospf6 external route hash");
+ return aggr;
+}
+
+static void ospf6_external_aggr_add(struct ospf6 *ospf6,
+ struct ospf6_external_aggr_rt *aggr)
+{
+ struct route_node *rn;
+
+ if (IS_OSPF6_DEBUG_AGGR)
+ zlog_debug("%s: Adding Aggregate route to Aggr table (%pFX)",
+ __func__,
+ &aggr->p);
+
+ rn = route_node_get(ospf6->rt_aggr_tbl, &aggr->p);
+ if (rn->info)
+ route_unlock_node(rn);
+ else
+ rn->info = aggr;
+}
+
+int ospf6_asbr_external_rt_no_advertise(struct ospf6 *ospf6,
+ struct prefix *p)
+{
+ struct ospf6_external_aggr_rt *aggr;
+ route_tag_t tag = 0;
+
+ aggr = ospf6_external_aggr_config_lookup(ospf6, p);
+ if (aggr) {
+ if (CHECK_FLAG(aggr->aggrflags,
+ OSPF6_EXTERNAL_AGGRT_NO_ADVERTISE))
+ return OSPF6_SUCCESS;
+
+ SET_FLAG(aggr->aggrflags, OSPF6_EXTERNAL_AGGRT_NO_ADVERTISE);
+
+ aggr->tag = tag;
+ aggr->metric = -1;
+
+ if (!OSPF6_EXTERNAL_RT_COUNT(aggr))
+ return OSPF6_SUCCESS;
+
+ ospf6_start_asbr_summary_delay_timer(ospf6, aggr,
+ OSPF6_ROUTE_AGGR_MODIFY);
+ } else {
+ aggr = ospf6_external_aggr_new(p);
+
+ if (!aggr)
+ return OSPF6_FAILURE;
+
+ SET_FLAG(aggr->aggrflags, OSPF6_EXTERNAL_AGGRT_NO_ADVERTISE);
+ ospf6_external_aggr_add(ospf6, aggr);
+ ospf6_start_asbr_summary_delay_timer(ospf6, aggr,
+ OSPF6_ROUTE_AGGR_ADD);
+ }
+
+ return OSPF6_SUCCESS;
+}
+
+struct ospf6_external_aggr_rt *
+ospf6_external_aggr_config_lookup(struct ospf6 *ospf6, struct prefix *p)
+{
+ struct route_node *rn;
+
+ rn = route_node_lookup(ospf6->rt_aggr_tbl, p);
+ if (rn) {
+ route_unlock_node(rn);
+ return rn->info;
+ }
+
+ return NULL;
+}
+
+
+int ospf6_external_aggr_config_set(struct ospf6 *ospf6, struct prefix *p,
+ route_tag_t tag, int metric, int mtype)
+{
+ struct ospf6_external_aggr_rt *aggregator;
+
+ aggregator = ospf6_external_aggr_config_lookup(ospf6, p);
+
+ if (aggregator) {
+ if (CHECK_FLAG(aggregator->aggrflags,
+ OSPF6_EXTERNAL_AGGRT_NO_ADVERTISE))
+ UNSET_FLAG(aggregator->aggrflags,
+ OSPF6_EXTERNAL_AGGRT_NO_ADVERTISE);
+ else if ((aggregator->tag == tag)
+ && (aggregator->metric == metric)
+ && (aggregator->mtype == mtype))
+ return OSPF6_SUCCESS;
+
+ aggregator->tag = tag;
+ aggregator->metric = metric;
+ aggregator->mtype = mtype;
+
+ ospf6_start_asbr_summary_delay_timer(ospf6, aggregator,
+ OSPF6_ROUTE_AGGR_MODIFY);
+ } else {
+ aggregator = ospf6_external_aggr_new(p);
+ if (!aggregator)
+ return OSPF6_FAILURE;
+
+ aggregator->tag = tag;
+ aggregator->metric = metric;
+ aggregator->mtype = mtype;
+
+ ospf6_external_aggr_add(ospf6, aggregator);
+ ospf6_start_asbr_summary_delay_timer(ospf6, aggregator,
+ OSPF6_ROUTE_AGGR_ADD);
+ }
+
+ return OSPF6_SUCCESS;
+}
+
+int ospf6_external_aggr_config_unset(struct ospf6 *ospf6,
+ struct prefix *p)
+{
+ struct route_node *rn;
+ struct ospf6_external_aggr_rt *aggr;
+
+ rn = route_node_lookup(ospf6->rt_aggr_tbl, p);
+ if (!rn)
+ return OSPF6_INVALID;
+
+ aggr = rn->info;
+
+ route_unlock_node(rn);
+
+ if (!OSPF6_EXTERNAL_RT_COUNT(aggr)) {
+ ospf6_asbr_summary_config_delete(ospf6, rn);
+ ospf6_external_aggregator_free(aggr);
+ return OSPF6_SUCCESS;
+ }
+
+ ospf6_start_asbr_summary_delay_timer(ospf6, aggr,
+ OSPF6_ROUTE_AGGR_DEL);
+
+ return OSPF6_SUCCESS;
+}
+
+void ospf6_handle_external_lsa_origination(struct ospf6 *ospf6,
+ struct ospf6_route *rt,
+ struct prefix *p)
+{
+
+ struct ospf6_external_aggr_rt *aggr;
+ struct ospf6_external_info *info;
+ struct prefix prefix_id;
+ struct route_node *node;
+
+ if (!is_default_prefix(p)) {
+ aggr = ospf6_external_aggr_match(ospf6,
+ p);
+
+ if (aggr) {
+
+ if (IS_OSPF6_DEBUG_AGGR)
+ zlog_debug("%s: Send Aggregate LSA (%pFX)",
+ __func__,
+ &aggr->p);
+
+ ospf6_originate_summary_lsa(
+ ospf6, aggr, rt);
+
+ /* Handling the case where the
+ * external route prefix
+ * and aggegate prefix is same
+ * If same dont flush the
+ * originated
+ * external LSA.
+ */
+ ospf6_handle_aggregated_exnl_rt(
+ ospf6, aggr, rt);
+ return;
+ }
+ }
+
+ info = rt->route_option;
+
+ /* When the info->id = 0, it means it is being originated for the
+ * first time.
+ */
+ if (!info->id) {
+ info->id = ospf6->external_id++;
+
+ /* create/update binding in external_id_table */
+ prefix_id.family = AF_INET;
+ prefix_id.prefixlen = 32;
+ prefix_id.u.prefix4.s_addr = htonl(info->id);
+ node = route_node_get(ospf6->external_id_table, &prefix_id);
+ node->info = rt;
+
+ } else {
+ prefix_id.family = AF_INET;
+ prefix_id.prefixlen = 32;
+ prefix_id.u.prefix4.s_addr = htonl(info->id);
+ }
+
+ rt->path.origin.id = htonl(info->id);
+
+ if (IS_OSPF6_DEBUG_ASBR) {
+ zlog_debug("Advertise new AS-External Id:%pI4 prefix %pFX metric %u",
+ &prefix_id.u.prefix4, p, rt->path.metric_type);
+ }
+
+ ospf6_originate_type5_type7_lsas(rt, ospf6);
+
+}
+
+void ospf6_unset_all_aggr_flag(struct ospf6 *ospf6)
+{
+ struct route_node *rn = NULL;
+ struct ospf6_external_aggr_rt *aggr;
+
+ if (IS_OSPF6_DEBUG_AGGR)
+ zlog_debug("Unset the origination bit for all aggregator");
+
+ /* Resetting the running external ID counter so that the origination
+ * of external LSAs starts from the beginning 0.0.0.1
+ */
+ ospf6->external_id = OSPF6_EXT_INIT_LS_ID;
+
+ for (rn = route_top(ospf6->rt_aggr_tbl); rn; rn = route_next(rn)) {
+ if (!rn->info)
+ continue;
+
+ aggr = rn->info;
+
+ UNSET_FLAG(aggr->aggrflags, OSPF6_EXTERNAL_AGGRT_ORIGINATED);
+ }
+}
diff --git a/ospf6d/ospf6_asbr.h b/ospf6d/ospf6_asbr.h
index 8f2135ef30..0aa1374a46 100644
--- a/ospf6d/ospf6_asbr.h
+++ b/ospf6d/ospf6_asbr.h
@@ -46,6 +46,52 @@ struct ospf6_external_info {
route_tag_t tag;
ifindex_t ifindex;
+
+};
+
+/* OSPF6 ASBR Summarisation */
+typedef enum {
+ OSPF6_ROUTE_AGGR_NONE = 0,
+ OSPF6_ROUTE_AGGR_ADD,
+ OSPF6_ROUTE_AGGR_DEL,
+ OSPF6_ROUTE_AGGR_MODIFY
+} ospf6_aggr_action_t;
+
+#define OSPF6_EXTERNAL_AGGRT_NO_ADVERTISE 0x1
+#define OSPF6_EXTERNAL_AGGRT_ORIGINATED 0x2
+
+#define OSPF6_EXTERNAL_RT_COUNT(aggr) \
+ (((struct ospf6_external_aggr_rt *)aggr)->match_extnl_hash->count)
+
+struct ospf6_external_aggr_rt {
+ /* range address and masklen */
+ struct prefix p;
+
+ /* use bits for OSPF6_EXTERNAL_AGGRT_NO_ADVERTISE and
+ * OSPF6_EXTERNAL_AGGRT_ORIGINATED
+ */
+ uint16_t aggrflags;
+
+ /* To store external metric-type */
+ uint8_t mtype;
+
+ /* Route tag for summary address */
+ route_tag_t tag;
+
+ /* To store aggregated metric config */
+ int metric;
+
+ /* To Store the LS ID when LSA is originated */
+ uint32_t id;
+
+ /* Action to be done after delay timer expiry */
+ int action;
+
+ /* OSPFv3 route generated by summary address. */
+ struct ospf6_route *route;
+
+ /* Hash table of matching external routes */
+ struct hash *match_extnl_hash;
};
/* AS-External-LSA */
@@ -105,12 +151,36 @@ extern void install_element_ospf6_debug_asbr(void);
extern void ospf6_asbr_update_route_ecmp_path(struct ospf6_route *old,
struct ospf6_route *route,
struct ospf6 *ospf6);
-extern void ospf6_asbr_distribute_list_update(int type, struct ospf6 *ospf6);
+extern void ospf6_asbr_distribute_list_update(struct ospf6 *ospf6,
+ struct ospf6_redist *red);
struct ospf6_redist *ospf6_redist_lookup(struct ospf6 *ospf6, int type,
unsigned short instance);
extern void ospf6_asbr_routemap_update(const char *mapname);
-extern void ospf6_as_external_lsa_originate(struct ospf6_route *route,
- struct ospf6 *ospf6);
+extern struct ospf6_lsa *
+ospf6_as_external_lsa_originate(struct ospf6_route *route,
+ struct ospf6 *ospf6);
extern void ospf6_asbr_status_update(struct ospf6 *ospf6, int status);
+int ospf6_asbr_external_rt_advertise(struct ospf6 *ospf6,
+ struct prefix *p);
+int ospf6_external_aggr_delay_timer_set(struct ospf6 *ospf6,
+ unsigned int interval);
+int ospf6_asbr_external_rt_no_advertise(struct ospf6 *ospf6,
+ struct prefix *p);
+
+struct ospf6_external_aggr_rt *
+ospf6_external_aggr_config_lookup(struct ospf6 *ospf6, struct prefix *p);
+
+int ospf6_external_aggr_config_set(struct ospf6 *ospf6, struct prefix *p,
+ route_tag_t tag, int metric, int mtype);
+
+int ospf6_external_aggr_config_unset(struct ospf6 *ospf6,
+ struct prefix *p);
+void ospf6_handle_external_lsa_origination(struct ospf6 *ospf6,
+ struct ospf6_route *rt,
+ struct prefix *p);
+void ospf6_external_aggregator_free(struct ospf6_external_aggr_rt *aggr);
+void ospf6_unset_all_aggr_flag(struct ospf6 *ospf6);
+void ospf6_fill_aggr_route_details(struct ospf6 *ospf6,
+ struct ospf6_external_aggr_rt *aggr);
#endif /* OSPF6_ASBR_H */
diff --git a/ospf6d/ospf6_flood.c b/ospf6d/ospf6_flood.c
index 05b43189e9..3d52597161 100644
--- a/ospf6d/ospf6_flood.c
+++ b/ospf6d/ospf6_flood.c
@@ -89,6 +89,16 @@ void ospf6_lsa_originate(struct ospf6_lsa *lsa)
struct ospf6_lsa *old;
struct ospf6_lsdb *lsdb_self;
+ if (lsa->header->adv_router == INADDR_ANY) {
+ if (IS_OSPF6_DEBUG_ORIGINATE_TYPE(lsa->header->type))
+ zlog_debug(
+ "Refusing to originate LSA (zero router ID): %s",
+ lsa->name);
+
+ ospf6_lsa_delete(lsa);
+ return;
+ }
+
/* find previous LSA */
old = ospf6_lsdb_lookup(lsa->header->type, lsa->header->id,
lsa->header->adv_router, lsa->lsdb);
@@ -106,7 +116,7 @@ void ospf6_lsa_originate(struct ospf6_lsa *lsa)
lsdb_self = ospf6_get_scoped_lsdb_self(lsa);
ospf6_lsdb_add(ospf6_lsa_copy(lsa), lsdb_self);
- lsa->refresh = NULL;
+ THREAD_OFF(lsa->refresh);
thread_add_timer(master, ospf6_lsa_refresh, lsa, OSPF_LS_REFRESH_TIME,
&lsa->refresh);
@@ -139,6 +149,31 @@ void ospf6_lsa_originate_interface(struct ospf6_lsa *lsa,
ospf6_lsa_originate(lsa);
}
+void ospf6_remove_id_from_external_id_table(struct ospf6 *ospf6,
+ uint32_t id)
+{
+ struct prefix prefix_id;
+ struct route_node *node;
+
+ /* remove binding in external_id_table */
+ prefix_id.family = AF_INET;
+ prefix_id.prefixlen = 32;
+ prefix_id.u.prefix4.s_addr = id;
+ node = route_node_lookup(ospf6->external_id_table, &prefix_id);
+ assert(node);
+ node->info = NULL;
+ route_unlock_node(node); /* to free the lookup lock */
+ route_unlock_node(node); /* to free the original lock */
+
+}
+
+void ospf6_external_lsa_purge(struct ospf6 *ospf6, struct ospf6_lsa *lsa)
+{
+ ospf6_lsa_purge(lsa);
+
+ ospf6_remove_id_from_external_id_table(ospf6, lsa->header->id);
+}
+
void ospf6_lsa_purge(struct ospf6_lsa *lsa)
{
struct ospf6_lsa *self;
@@ -299,7 +334,7 @@ void ospf6_flood_interface(struct ospf6_neighbor *from, struct ospf6_lsa *lsa,
{
struct listnode *node, *nnode;
struct ospf6_neighbor *on;
- struct ospf6_lsa *req;
+ struct ospf6_lsa *req, *old;
int retrans_added = 0;
int is_debug = 0;
@@ -408,12 +443,27 @@ void ospf6_flood_interface(struct ospf6_neighbor *from, struct ospf6_lsa *lsa,
if (is_debug)
zlog_debug("Add retrans-list of neighbor %s ",
on->name);
- ospf6_increment_retrans_count(lsa);
- ospf6_lsdb_add(ospf6_lsa_copy(lsa), on->retrans_list);
- thread_add_timer(master, ospf6_lsupdate_send_neighbor,
- on, on->ospf6_if->rxmt_interval,
- &on->thread_send_lsupdate);
- retrans_added++;
+
+ /* Do not increment the retrans count if the lsa is
+ * already present in the retrans list.
+ */
+ old = ospf6_lsdb_lookup(
+ lsa->header->type, lsa->header->id,
+ lsa->header->adv_router, on->retrans_list);
+ if (!old) {
+ if (is_debug)
+ zlog_debug(
+ "Increment %s from retrans_list of %s",
+ lsa->name, on->name);
+ ospf6_increment_retrans_count(lsa);
+ ospf6_lsdb_add(ospf6_lsa_copy(lsa),
+ on->retrans_list);
+ thread_add_timer(
+ master, ospf6_lsupdate_send_neighbor,
+ on, on->ospf6_if->rxmt_interval,
+ &on->thread_send_lsupdate);
+ retrans_added++;
+ }
}
}
diff --git a/ospf6d/ospf6_flood.h b/ospf6d/ospf6_flood.h
index 5515a1c3fe..4e4fc55ed4 100644
--- a/ospf6d/ospf6_flood.h
+++ b/ospf6d/ospf6_flood.h
@@ -39,6 +39,9 @@ extern void ospf6_lsa_originate_area(struct ospf6_lsa *lsa,
struct ospf6_area *oa);
extern void ospf6_lsa_originate_interface(struct ospf6_lsa *lsa,
struct ospf6_interface *oi);
+void ospf6_remove_id_from_external_id_table(struct ospf6 *ospf6,
+ uint32_t id);
+void ospf6_external_lsa_purge(struct ospf6 *ospf6, struct ospf6_lsa *lsa);
extern void ospf6_lsa_purge(struct ospf6_lsa *lsa);
extern void ospf6_lsa_purge_multi_ls_id(struct ospf6_area *oa,
diff --git a/ospf6d/ospf6_interface.c b/ospf6d/ospf6_interface.c
index 1e75fc60f6..a169b9c60e 100644
--- a/ospf6d/ospf6_interface.c
+++ b/ospf6d/ospf6_interface.c
@@ -385,7 +385,6 @@ void ospf6_interface_connected_route_update(struct interface *ifp)
struct connected *c;
struct listnode *node, *nnode;
struct in6_addr nh_addr;
- int count = 0, max_addr_count;
oi = (struct ospf6_interface *)ifp->info;
if (oi == NULL)
@@ -404,22 +403,10 @@ void ospf6_interface_connected_route_update(struct interface *ifp)
/* update "route to advertise" interface route table */
ospf6_route_remove_all(oi->route_connected);
- if (oi->ifmtu >= OSPF6_JUMBO_MTU)
- max_addr_count = OSPF6_MAX_IF_ADDRS_JUMBO;
- else
- max_addr_count = OSPF6_MAX_IF_ADDRS;
-
for (ALL_LIST_ELEMENTS(oi->interface->connected, node, nnode, c)) {
if (c->address->family != AF_INET6)
continue;
- /* number of interface addresses supported is based on MTU
- * size of OSPFv3 packet
- */
- count++;
- if (count >= max_addr_count)
- break;
-
CONTINUE_IF_ADDRESS_LINKLOCAL(IS_OSPF6_DEBUG_INTERFACE,
c->address);
CONTINUE_IF_ADDRESS_UNSPECIFIED(IS_OSPF6_DEBUG_INTERFACE,
@@ -448,7 +435,7 @@ void ospf6_interface_connected_route_update(struct interface *ifp)
}
}
- route = ospf6_route_create();
+ route = ospf6_route_create(oi->area->ospf6);
memcpy(&route->prefix, c->address, sizeof(struct prefix));
apply_mask(&route->prefix);
route->type = OSPF6_DEST_TYPE_NETWORK;
@@ -680,6 +667,43 @@ static uint8_t dr_election(struct ospf6_interface *oi)
return next_state;
}
+#ifdef __FreeBSD__
+
+#include <ifaddrs.h>
+
+static bool ifmaddr_check(ifindex_t ifindex, struct in6_addr *addr)
+{
+ struct ifmaddrs *ifmap, *ifma;
+ struct sockaddr_dl *sdl;
+ struct sockaddr_in6 *sin6;
+ bool found = false;
+
+ if (getifmaddrs(&ifmap) != 0)
+ return false;
+
+ for (ifma = ifmap; ifma; ifma = ifma->ifma_next) {
+ if (ifma->ifma_name == NULL || ifma->ifma_addr == NULL)
+ continue;
+ if (ifma->ifma_name->sa_family != AF_LINK)
+ continue;
+ if (ifma->ifma_addr->sa_family != AF_INET6)
+ continue;
+ sdl = (struct sockaddr_dl *)ifma->ifma_name;
+ sin6 = (struct sockaddr_in6 *)ifma->ifma_addr;
+ if (sdl->sdl_index == ifindex
+ && memcmp(&sin6->sin6_addr, addr, IPV6_MAX_BYTELEN) == 0) {
+ found = true;
+ break;
+ }
+ }
+
+ if (ifmap)
+ freeifmaddrs(ifmap);
+
+ return found;
+}
+
+#endif /* __FreeBSD__ */
/* Interface State Machine */
int interface_up(struct thread *thread)
@@ -693,11 +717,7 @@ int interface_up(struct thread *thread)
if (!oi->type_cfg)
oi->type = ospf6_default_iftype(oi->interface);
- /*
- * Remove old pointer. If this thread wasn't a timer this
- * operation won't make a difference, because it is already NULL.
- */
- oi->thread_sso = NULL;
+ thread_cancel(&oi->thread_sso);
if (IS_OSPF6_DEBUG_INTERFACE)
zlog_debug("Interface Event %s: [InterfaceUp]",
@@ -733,20 +753,24 @@ int interface_up(struct thread *thread)
/* If no area assigned, return */
if (oi->area == NULL) {
zlog_warn(
- "%s: Not scheduleing Hello for %s as there is no area assigned yet",
+ "%s: Not scheduling Hello for %s as there is no area assigned yet",
__func__, oi->interface->name);
return 0;
}
#ifdef __FreeBSD__
/*
- * XXX: Schedule IPv6 group join for later, otherwise we might
- * lose the multicast group registration caused by IPv6 group
- * leave race.
+ * There's a delay in FreeBSD between issuing a command to leave a
+ * multicast group and an actual leave. If we execute "no router ospf6"
+ * and "router ospf6" fast enough, we can end up in a situation when OS
+ * performs the leave later than it performs the join and the interface
+ * remains without a multicast group. We have to do the join only after
+ * the interface actually left the group.
*/
- if (oi->sso_try_cnt == 0) {
- oi->sso_try_cnt++;
- zlog_info("Scheduling %s for sso", oi->interface->name);
+ if (ifmaddr_check(oi->interface->ifindex, &allspfrouters6)) {
+ zlog_info(
+ "Interface %s is still in all routers group, rescheduling for SSO",
+ oi->interface->name);
thread_add_timer(master, interface_up, oi,
OSPF6_INTERFACE_SSO_RETRY_INT,
&oi->thread_sso);
@@ -784,7 +808,9 @@ int interface_up(struct thread *thread)
}
/* decide next interface state */
- if (oi->type == OSPF_IFTYPE_POINTOPOINT) {
+ if (oi->type == OSPF_IFTYPE_LOOPBACK) {
+ ospf6_interface_state_change(OSPF6_INTERFACE_LOOPBACK, oi);
+ } else if (oi->type == OSPF_IFTYPE_POINTOPOINT) {
ospf6_interface_state_change(OSPF6_INTERFACE_POINTTOPOINT, oi);
} else if (oi->priority == 0)
ospf6_interface_state_change(OSPF6_INTERFACE_DROTHER, oi);
@@ -1691,7 +1717,6 @@ DEFUN (ipv6_ospf6_area,
int idx_ipv4 = 3;
uint32_t area_id;
int format;
- int ipv6_count = 0;
assert(ifp);
@@ -1706,23 +1731,6 @@ DEFUN (ipv6_ospf6_area,
return CMD_SUCCESS;
}
- /* if more than OSPF6_MAX_IF_ADDRS are configured on this interface
- * then don't allow ospfv3 to be configured
- */
- ipv6_count = connected_count_by_family(ifp, AF_INET6);
- if (oi->ifmtu == OSPF6_DEFAULT_MTU && ipv6_count > OSPF6_MAX_IF_ADDRS) {
- vty_out(vty,
- "can not configure OSPFv3 on if %s, must have less than %d interface addresses but has %d addresses\n",
- ifp->name, OSPF6_MAX_IF_ADDRS, ipv6_count);
- return CMD_WARNING_CONFIG_FAILED;
- } else if (oi->ifmtu >= OSPF6_JUMBO_MTU
- && ipv6_count > OSPF6_MAX_IF_ADDRS_JUMBO) {
- vty_out(vty,
- "can not configure OSPFv3 on if %s, must have less than %d interface addresses but has %d addresses\n",
- ifp->name, OSPF6_MAX_IF_ADDRS_JUMBO, ipv6_count);
- return CMD_WARNING_CONFIG_FAILED;
- }
-
if (str2area_id(argv[idx_ipv4]->arg, &area_id, &format)) {
vty_out(vty, "Malformed Area-ID: %s\n", argv[idx_ipv4]->arg);
return CMD_WARNING_CONFIG_FAILED;
@@ -2576,15 +2584,6 @@ static int config_write_interface(struct vty *vty)
return write;
}
-static int config_write_ospf6_interface(struct vty *vty, struct vrf *vrf);
-static struct cmd_node interface_node = {
- .name = "interface",
- .node = INTERFACE_NODE,
- .parent_node = CONFIG_NODE,
- .prompt = "%s(config-if)# ",
- .config_write = config_write_interface,
-};
-
static int ospf6_ifp_create(struct interface *ifp)
{
if (IS_OSPF6_DEBUG_ZEBRA(RECV))
@@ -2642,8 +2641,7 @@ static int ospf6_ifp_destroy(struct interface *ifp)
void ospf6_interface_init(void)
{
/* Install interface node. */
- install_node(&interface_node);
- if_cmd_init();
+ if_cmd_init(config_write_interface);
if_zapi_callbacks(ospf6_ifp_create, ospf6_ifp_up,
ospf6_ifp_down, ospf6_ifp_destroy);
diff --git a/ospf6d/ospf6_interface.h b/ospf6d/ospf6_interface.h
index c9cd74b691..b5efca743e 100644
--- a/ospf6d/ospf6_interface.h
+++ b/ospf6d/ospf6_interface.h
@@ -201,7 +201,6 @@ extern void ospf6_interface_disable(struct ospf6_interface *);
extern void ospf6_interface_state_update(struct interface *);
extern void ospf6_interface_connected_route_update(struct interface *);
-extern void ospf6_interface_connected_route_add(struct connected *);
extern struct in6_addr *
ospf6_interface_get_global_address(struct interface *ifp);
diff --git a/ospf6d/ospf6_intra.c b/ospf6d/ospf6_intra.c
index c971c6180e..e4db8f3a02 100644
--- a/ospf6d/ospf6_intra.c
+++ b/ospf6d/ospf6_intra.c
@@ -767,7 +767,6 @@ int ospf6_link_lsa_originate(struct thread *thread)
struct ospf6_link_lsa *link_lsa;
struct ospf6_route *route;
struct ospf6_prefix *op;
- int count, max_addr_count;
oi = (struct ospf6_interface *)THREAD_ARG(thread);
oi->thread_link_lsa = NULL;
@@ -811,30 +810,22 @@ int ospf6_link_lsa_originate(struct thread *thread)
memcpy(link_lsa->options, oi->area->options, 3);
memcpy(&link_lsa->linklocal_addr, oi->linklocal_addr,
sizeof(struct in6_addr));
+ link_lsa->prefix_num = htonl(oi->route_connected->count);
op = (struct ospf6_prefix *)((caddr_t)link_lsa
+ sizeof(struct ospf6_link_lsa));
- /* connected prefix to advertise, number of interface addresses
- * supported is based on MTU size of OSPFv3 packets
- */
- if (oi->ifmtu >= OSPF6_JUMBO_MTU)
- max_addr_count = OSPF6_MAX_IF_ADDRS_JUMBO;
- else
- max_addr_count = OSPF6_MAX_IF_ADDRS;
- for (route = ospf6_route_head(oi->route_connected), count = 0;
- route && count < max_addr_count;
- route = ospf6_route_next(route), count++) {
+ /* connected prefix to advertise */
+ for (route = ospf6_route_head(oi->route_connected); route;
+ route = ospf6_route_next(route)) {
op->prefix_length = route->prefix.prefixlen;
- op->prefix_options = route->path.prefix_options;
+ op->prefix_options = route->prefix_options;
op->prefix_metric = htons(0);
memcpy(OSPF6_PREFIX_BODY(op), &route->prefix.u.prefix6,
OSPF6_PREFIX_SPACE(op->prefix_length));
op = OSPF6_PREFIX_NEXT(op);
}
- link_lsa->prefix_num = htonl(count);
-
/* Fill LSA Header */
lsa_header->age = 0;
lsa_header->type = htons(OSPF6_LSTYPE_LINK);
@@ -1014,7 +1005,6 @@ int ospf6_intra_prefix_lsa_originate_stub(struct thread *thread)
unsigned short prefix_num = 0;
struct ospf6_route_table *route_advertise;
int ls_id = 0;
- int count, max_addr_count;
oa = (struct ospf6_area *)THREAD_ARG(thread);
oa->thread_intra_prefix_lsa = NULL;
@@ -1060,8 +1050,6 @@ int ospf6_intra_prefix_lsa_originate_stub(struct thread *thread)
intra_prefix_lsa->ref_adv_router = oa->ospf6->router_id;
route_advertise = ospf6_route_table_create(0, 0);
- route_advertise->hook_add = NULL;
- route_advertise->hook_remove = NULL;
for (ALL_LIST_ELEMENTS_RO(oa->if_list, i, oi)) {
if (oi->state == OSPF6_INTERFACE_DOWN) {
@@ -1090,14 +1078,8 @@ int ospf6_intra_prefix_lsa_originate_stub(struct thread *thread)
zlog_debug(" Interface %s:", oi->interface->name);
/* connected prefix to advertise */
- if (oi->ifmtu >= OSPF6_JUMBO_MTU)
- max_addr_count = OSPF6_MAX_IF_ADDRS_JUMBO;
- else
- max_addr_count = OSPF6_MAX_IF_ADDRS;
-
- for (route = ospf6_route_head(oi->route_connected), count = 0;
- route && count < max_addr_count;
- route = ospf6_route_best_next(route), count++) {
+ for (route = ospf6_route_head(oi->route_connected); route;
+ route = ospf6_route_best_next(route)) {
if (IS_OSPF6_DEBUG_ORIGINATE(INTRA_PREFIX))
zlog_debug(" include %pFX", &route->prefix);
ospf6_route_add(ospf6_route_copy(route),
@@ -1193,7 +1175,7 @@ int ospf6_intra_prefix_lsa_originate_stub(struct thread *thread)
}
op->prefix_length = route->prefix.prefixlen;
- op->prefix_options = route->path.prefix_options;
+ op->prefix_options = route->prefix_options;
op->prefix_metric = htons(route->path.cost);
memcpy(OSPF6_PREFIX_BODY(op), &route->prefix.u.prefix6,
OSPF6_PREFIX_SPACE(op->prefix_length));
@@ -1312,8 +1294,6 @@ int ospf6_intra_prefix_lsa_originate_transit(struct thread *thread)
/* connected prefix to advertise */
route_advertise = ospf6_route_table_create(0, 0);
- route_advertise->hook_add = NULL;
- route_advertise->hook_remove = NULL;
type = ntohs(OSPF6_LSTYPE_LINK);
for (ALL_LSDB_TYPED(oi->lsdb, type, lsa)) {
@@ -1347,7 +1327,7 @@ int ospf6_intra_prefix_lsa_originate_transit(struct thread *thread)
|| current + OSPF6_PREFIX_SIZE(op) > end)
break;
- route = ospf6_route_create();
+ route = ospf6_route_create(oi->area->ospf6);
route->type = OSPF6_DEST_TYPE_NETWORK;
route->prefix.family = AF_INET6;
@@ -1356,6 +1336,7 @@ int ospf6_intra_prefix_lsa_originate_transit(struct thread *thread)
sizeof(struct in6_addr));
memcpy(&route->prefix.u.prefix6, OSPF6_PREFIX_BODY(op),
OSPF6_PREFIX_SPACE(op->prefix_length));
+ route->prefix_options = op->prefix_options;
route->path.origin.type = lsa->header->type;
route->path.origin.id = lsa->header->id;
@@ -1363,7 +1344,6 @@ int ospf6_intra_prefix_lsa_originate_transit(struct thread *thread)
route->path.options[0] = link_lsa->options[0];
route->path.options[1] = link_lsa->options[1];
route->path.options[2] = link_lsa->options[2];
- route->path.prefix_options = op->prefix_options;
route->path.area_id = oi->area->area_id;
route->path.type = OSPF6_PATH_TYPE_INTRA;
@@ -1384,7 +1364,7 @@ int ospf6_intra_prefix_lsa_originate_transit(struct thread *thread)
for (route = ospf6_route_head(route_advertise); route;
route = ospf6_route_best_next(route)) {
op->prefix_length = route->prefix.prefixlen;
- op->prefix_options = route->path.prefix_options;
+ op->prefix_options = route->prefix_options;
op->prefix_metric = htons(0);
memcpy(OSPF6_PREFIX_BODY(op), &route->prefix.u.prefix6,
OSPF6_PREFIX_SPACE(op->prefix_length));
@@ -1810,19 +1790,19 @@ void ospf6_intra_prefix_lsa_add(struct ospf6_lsa *lsa)
continue;
}
- route = ospf6_route_create();
+ route = ospf6_route_create(oa->ospf6);
memset(&route->prefix, 0, sizeof(struct prefix));
route->prefix.family = AF_INET6;
route->prefix.prefixlen = op->prefix_length;
ospf6_prefix_in6_addr(&route->prefix.u.prefix6,
intra_prefix_lsa, op);
+ route->prefix_options = op->prefix_options;
route->type = OSPF6_DEST_TYPE_NETWORK;
route->path.origin.type = lsa->header->type;
route->path.origin.id = lsa->header->id;
route->path.origin.adv_router = lsa->header->adv_router;
- route->path.prefix_options = op->prefix_options;
route->path.area_id = oa->area_id;
route->path.type = OSPF6_PATH_TYPE_INTRA;
route->path.metric_type = 1;
diff --git a/ospf6d/ospf6_lsa.c b/ospf6d/ospf6_lsa.c
index bab5fdaae8..9c03ce21ed 100644
--- a/ospf6d/ospf6_lsa.c
+++ b/ospf6d/ospf6_lsa.c
@@ -45,6 +45,10 @@
#include "ospf6_flood.h"
#include "ospf6d.h"
+#ifndef VTYSH_EXTRACT_PL
+#include "ospf6d/ospf6_lsa_clippy.c"
+#endif
+
DEFINE_MTYPE_STATIC(OSPF6D, OSPF6_LSA, "OSPF6 LSA");
DEFINE_MTYPE_STATIC(OSPF6D, OSPF6_LSA_HEADER, "OSPF6 LSA header");
DEFINE_MTYPE_STATIC(OSPF6D, OSPF6_LSA_SUMMARY, "OSPF6 LSA summary");
@@ -822,6 +826,8 @@ int ospf6_lsa_expire(struct thread *thread)
if (CHECK_FLAG(lsa->flag, OSPF6_LSA_HEADERONLY))
return 0; /* dbexchange will do something ... */
ospf6 = ospf6_get_by_lsdb(lsa);
+ assert(ospf6);
+
/* reinstall lsa */
ospf6_install_lsa(lsa);
@@ -994,6 +1000,30 @@ static char *ospf6_lsa_handler_name(const struct ospf6_lsa_handler *h)
return buf;
}
+DEFPY (debug_ospf6_lsa_aggregation,
+ debug_ospf6_lsa_aggregation_cmd,
+ "[no] debug ospf6 lsa aggregation",
+ NO_STR
+ DEBUG_STR
+ OSPF6_STR
+ "Debug Link State Advertisements (LSAs)\n"
+ "External LSA Aggregation\n")
+{
+
+ struct ospf6_lsa_handler *handler;
+
+ handler = ospf6_get_lsa_handler(OSPF6_LSTYPE_AS_EXTERNAL);
+ if (handler == NULL)
+ return CMD_WARNING_CONFIG_FAILED;
+
+ if (no)
+ UNSET_FLAG(handler->lh_debug, OSPF6_LSA_DEBUG_AGGR);
+ else
+ SET_FLAG(handler->lh_debug, OSPF6_LSA_DEBUG_AGGR);
+
+ return CMD_SUCCESS;
+}
+
DEFUN (debug_ospf6_lsa_type,
debug_ospf6_lsa_hex_cmd,
"debug ospf6 lsa <router|network|inter-prefix|inter-router|as-external|link|intra-prefix|unknown> [<originate|examine|flooding>]",
@@ -1105,6 +1135,9 @@ void install_element_ospf6_debug_lsa(void)
install_element(ENABLE_NODE, &no_debug_ospf6_lsa_hex_cmd);
install_element(CONFIG_NODE, &debug_ospf6_lsa_hex_cmd);
install_element(CONFIG_NODE, &no_debug_ospf6_lsa_hex_cmd);
+
+ install_element(ENABLE_NODE, &debug_ospf6_lsa_aggregation_cmd);
+ install_element(CONFIG_NODE, &debug_ospf6_lsa_aggregation_cmd);
}
int config_write_ospf6_debug_lsa(struct vty *vty)
@@ -1128,6 +1161,8 @@ int config_write_ospf6_debug_lsa(struct vty *vty)
if (CHECK_FLAG(handler->lh_debug, OSPF6_LSA_DEBUG_FLOOD))
vty_out(vty, "debug ospf6 lsa %s flooding\n",
ospf6_lsa_handler_name(handler));
+ if (CHECK_FLAG(handler->lh_debug, OSPF6_LSA_DEBUG_AGGR))
+ vty_out(vty, "debug ospf6 lsa aggregation\n");
}
return 0;
diff --git a/ospf6d/ospf6_lsa.h b/ospf6d/ospf6_lsa.h
index 15b0d4ebbc..4c95ee69bd 100644
--- a/ospf6d/ospf6_lsa.h
+++ b/ospf6d/ospf6_lsa.h
@@ -28,6 +28,7 @@
#define OSPF6_LSA_DEBUG_ORIGINATE 0x02
#define OSPF6_LSA_DEBUG_EXAMIN 0x04
#define OSPF6_LSA_DEBUG_FLOOD 0x08
+#define OSPF6_LSA_DEBUG_AGGR 0x10
/* OSPF LSA Default metric values */
#define DEFAULT_DEFAULT_METRIC 20
@@ -51,6 +52,8 @@
(ospf6_lstype_debug(type) & OSPF6_LSA_DEBUG_EXAMIN)
#define IS_OSPF6_DEBUG_FLOOD_TYPE(type) \
(ospf6_lstype_debug(type) & OSPF6_LSA_DEBUG_FLOOD)
+#define IS_OSPF6_DEBUG_AGGR \
+ (ospf6_lstype_debug(OSPF6_LSTYPE_AS_EXTERNAL) & OSPF6_LSA_DEBUG_AGGR) \
/* LSA definition */
@@ -263,4 +266,6 @@ extern void install_element_ospf6_debug_lsa(void);
extern void ospf6_lsa_age_set(struct ospf6_lsa *lsa);
extern void ospf6_flush_self_originated_lsas_now(struct ospf6 *ospf6);
extern struct ospf6 *ospf6_get_by_lsdb(struct ospf6_lsa *lsa);
+struct ospf6_lsa *ospf6_find_external_lsa(struct ospf6 *ospf6,
+ struct prefix *p);
#endif /* OSPF6_LSA_H */
diff --git a/ospf6d/ospf6_lsdb.c b/ospf6d/ospf6_lsdb.c
index 304f03fde8..039c65d739 100644
--- a/ospf6d/ospf6_lsdb.c
+++ b/ospf6d/ospf6_lsdb.c
@@ -30,6 +30,7 @@
#include "ospf6_proto.h"
#include "ospf6_lsa.h"
#include "ospf6_lsdb.h"
+#include "ospf6_asbr.h"
#include "ospf6_route.h"
#include "ospf6d.h"
#include "bitfield.h"
@@ -194,6 +195,28 @@ struct ospf6_lsa *ospf6_lsdb_lookup(uint16_t type, uint32_t id,
return (struct ospf6_lsa *)node->info;
}
+struct ospf6_lsa *ospf6_find_external_lsa(struct ospf6 *ospf6, struct prefix *p)
+{
+ struct ospf6_route *match;
+ struct ospf6_lsa *lsa;
+ struct ospf6_external_info *info;
+
+ match = ospf6_route_lookup(p, ospf6->external_table);
+ if (match == NULL) {
+ if (IS_OSPF6_DEBUG_ASBR)
+ zlog_debug("No such route %pFX to withdraw", p);
+
+ return NULL;
+ }
+
+ info = match->route_option;
+ assert(info);
+
+ lsa = ospf6_lsdb_lookup(htons(OSPF6_LSTYPE_AS_EXTERNAL),
+ htonl(info->id), ospf6->router_id, ospf6->lsdb);
+ return lsa;
+}
+
struct ospf6_lsa *ospf6_lsdb_lookup_next(uint16_t type, uint32_t id,
uint32_t adv_router,
struct ospf6_lsdb *lsdb)
diff --git a/ospf6d/ospf6_message.c b/ospf6d/ospf6_message.c
index 817e5372ea..549f5668b9 100644
--- a/ospf6d/ospf6_message.c
+++ b/ospf6d/ospf6_message.c
@@ -444,9 +444,9 @@ static void ospf6_hello_recv(struct in6_addr *src, struct in6_addr *dst,
/* check latency against hello period */
if (on->hello_in)
latency = monotime_since(&on->last_hello, NULL)
- - (oi->hello_interval * 1000000);
+ - ((int64_t)oi->hello_interval * 1000000);
/* log if latency exceeds the hello period */
- if (latency > (oi->hello_interval * 1000000))
+ if (latency > ((int64_t)oi->hello_interval * 1000000))
zlog_warn("%s RX %pI4 high latency %" PRId64 "us.", __func__,
&on->router_id, latency);
on->last_hello = timestamp;
@@ -1897,7 +1897,6 @@ static int ospf6_write(struct thread *thread)
struct ospf6_header *oh;
struct ospf6_packet *op;
struct listnode *node;
- char srcname[64], dstname[64];
struct iovec iovector[2];
int pkt_count = 0;
int len;
@@ -1934,48 +1933,62 @@ static int ospf6_write(struct thread *thread)
flog_err(EC_LIB_DEVELOPMENT,
"Could not send entire message");
- if (IS_OSPF6_DEBUG_MESSAGE(oh->type, SEND)) {
- inet_ntop(AF_INET6, &op->dst, dstname, sizeof(dstname));
- inet_ntop(AF_INET6, oi->linklocal_addr, srcname,
- sizeof(srcname));
+ if (IS_OSPF6_DEBUG_MESSAGE(oh->type, SEND_HDR)) {
zlog_debug("%s send on %s",
lookup_msg(ospf6_message_type_str, oh->type,
NULL),
oi->interface->name);
- zlog_debug(" src: %s", srcname);
- zlog_debug(" dst: %s", dstname);
+ zlog_debug(" src: %pI6", oi->linklocal_addr);
+ zlog_debug(" dst: %pI6", &op->dst);
+ switch (oh->type) {
+ case OSPF6_MESSAGE_TYPE_HELLO:
+ ospf6_hello_print(oh, OSPF6_ACTION_SEND);
+ break;
+ case OSPF6_MESSAGE_TYPE_DBDESC:
+ ospf6_dbdesc_print(oh, OSPF6_ACTION_SEND);
+ break;
+ case OSPF6_MESSAGE_TYPE_LSREQ:
+ ospf6_lsreq_print(oh, OSPF6_ACTION_SEND);
+ break;
+ case OSPF6_MESSAGE_TYPE_LSUPDATE:
+ ospf6_lsupdate_print(oh, OSPF6_ACTION_SEND);
+ break;
+ case OSPF6_MESSAGE_TYPE_LSACK:
+ ospf6_lsack_print(oh, OSPF6_ACTION_SEND);
+ break;
+ default:
+ zlog_debug("Unknown message");
+ assert(0);
+ break;
+ }
}
switch (oh->type) {
case OSPF6_MESSAGE_TYPE_HELLO:
monotime(&timestamp);
if (oi->hello_out)
latency = monotime_since(&oi->last_hello, NULL)
- - (oi->hello_interval * 1000000);
+ - ((int64_t)oi->hello_interval
+ * 1000000);
/* log if latency exceeds the hello period */
- if (latency > (oi->hello_interval * 1000000))
+ if (latency > ((int64_t)oi->hello_interval * 1000000))
zlog_warn("%s hello TX high latency %" PRId64
"us.",
__func__, latency);
oi->last_hello = timestamp;
oi->hello_out++;
- ospf6_hello_print(oh, OSPF6_ACTION_SEND);
break;
case OSPF6_MESSAGE_TYPE_DBDESC:
oi->db_desc_out++;
- ospf6_dbdesc_print(oh, OSPF6_ACTION_SEND);
break;
case OSPF6_MESSAGE_TYPE_LSREQ:
oi->ls_req_out++;
- ospf6_lsreq_print(oh, OSPF6_ACTION_SEND);
break;
case OSPF6_MESSAGE_TYPE_LSUPDATE:
oi->ls_upd_out++;
- ospf6_lsupdate_print(oh, OSPF6_ACTION_SEND);
break;
case OSPF6_MESSAGE_TYPE_LSACK:
oi->ls_ack_out++;
- ospf6_lsack_print(oh, OSPF6_ACTION_SEND);
break;
default:
zlog_debug("Unknown message");
@@ -2356,7 +2369,19 @@ static void ospf6_send_lsupdate(struct ospf6_neighbor *on,
}
if (oi) {
ospf6_packet_add(oi, op);
- OSPF6_MESSAGE_WRITE_ON(oi);
+ /* If ospf instance is being deleted, send the packet
+ * immediately
+ */
+ if ((oi->area == NULL) || (oi->area->ospf6 == NULL))
+ return;
+ if (oi->area->ospf6->inst_shutdown) {
+ if (oi->on_write_q == 0) {
+ listnode_add(oi->area->ospf6->oi_write_q, oi);
+ oi->on_write_q = 1;
+ }
+ thread_execute(master, ospf6_write, oi->area->ospf6, 0);
+ } else
+ OSPF6_MESSAGE_WRITE_ON(oi);
}
}
diff --git a/ospf6d/ospf6_nssa.c b/ospf6d/ospf6_nssa.c
index 9f8cdf8fb7..470a5b1338 100644
--- a/ospf6d/ospf6_nssa.c
+++ b/ospf6d/ospf6_nssa.c
@@ -1159,10 +1159,49 @@ static void ospf6_nssa_flush_area(struct ospf6_area *area)
}
}
-static void ospf6_area_nssa_update(struct ospf6_area *area)
+static void ospf6_check_and_originate_type7_lsa(struct ospf6_area *area)
{
struct ospf6_route *route;
+ struct route_node *rn = NULL;
+ struct ospf6_external_aggr_rt *aggr;
+
+ /* Loop through the external_table to find the LSAs originated
+ * without aggregation and originate type-7 LSAs for them.
+ */
+ for (route = ospf6_route_head(
+ area->ospf6->external_table);
+ route; route = ospf6_route_next(route)) {
+ /* This means the Type-5 LSA was originated for this route */
+ if (route->path.origin.id != 0)
+ ospf6_nssa_lsa_originate(route, area);
+
+ }
+
+ /* Loop through the aggregation table to originate type-7 LSAs
+ * for the aggregated type-5 LSAs
+ */
+ for (rn = route_top(area->ospf6->rt_aggr_tbl); rn;
+ rn = route_next(rn)) {
+ if (!rn->info)
+ continue;
+
+ aggr = rn->info;
+
+ if (CHECK_FLAG(aggr->aggrflags,
+ OSPF6_EXTERNAL_AGGRT_ORIGINATED)) {
+ if (IS_OSPF6_DEBUG_NSSA)
+ zlog_debug(
+ "Originating Type-7 LSAs for area %s",
+ area->name);
+
+ ospf6_nssa_lsa_originate(aggr->route, area);
+ }
+ }
+}
+
+static void ospf6_area_nssa_update(struct ospf6_area *area)
+{
if (IS_AREA_NSSA(area)) {
if (!ospf6_check_and_set_router_abr(area->ospf6))
OSPF6_OPT_CLEAR(area->options, OSPF6_OPT_E);
@@ -1194,10 +1233,7 @@ static void ospf6_area_nssa_update(struct ospf6_area *area)
zlog_debug("NSSA area %s", area->name);
/* Originate NSSA LSA */
- for (route = ospf6_route_head(
- area->ospf6->external_table);
- route; route = ospf6_route_next(route))
- ospf6_nssa_lsa_originate(route, area);
+ ospf6_check_and_originate_type7_lsa(area);
}
} else {
/* Disable NSSA */
@@ -1259,13 +1295,10 @@ void ospf6_nssa_lsa_originate(struct ospf6_route *route,
struct in6_addr *fwd_addr;
struct ospf6_as_external_lsa *as_external_lsa;
- char buf[PREFIX2STR_BUFFER];
caddr_t p;
- if (IS_OSPF6_DEBUG_ASBR || IS_OSPF6_DEBUG_ORIGINATE(AS_EXTERNAL)) {
- prefix2str(&route->prefix, buf, sizeof(buf));
- zlog_debug("Originate AS-External-LSA for %s", buf);
- }
+ if (IS_OSPF6_DEBUG_ASBR || IS_OSPF6_DEBUG_ORIGINATE(AS_EXTERNAL))
+ zlog_debug("Originate NSSA-LSA for %pFX", &route->prefix);
/* prepare buffer */
memset(buffer, 0, sizeof(buffer));
@@ -1296,7 +1329,7 @@ void ospf6_nssa_lsa_originate(struct ospf6_route *route,
as_external_lsa->prefix.prefix_length = route->prefix.prefixlen;
/* PrefixOptions */
- as_external_lsa->prefix.prefix_options = route->path.prefix_options;
+ as_external_lsa->prefix.prefix_options = route->prefix_options;
/* Set the P bit */
as_external_lsa->prefix.prefix_options |= OSPF6_PREFIX_OPTION_P;
@@ -1334,7 +1367,7 @@ void ospf6_nssa_lsa_originate(struct ospf6_route *route,
lsa_header->adv_router = area->ospf6->router_id;
lsa_header->seqnum =
ospf6_new_ls_seqnum(lsa_header->type, lsa_header->id,
- lsa_header->adv_router, area->ospf6->lsdb);
+ lsa_header->adv_router, area->lsdb);
lsa_header->length = htons((caddr_t)p - (caddr_t)lsa_header);
/* LSA checksum */
diff --git a/ospf6d/ospf6_route.c b/ospf6d/ospf6_route.c
index 0a026785f4..cd3139d28a 100644
--- a/ospf6d/ospf6_route.c
+++ b/ospf6d/ospf6_route.c
@@ -284,12 +284,21 @@ void ospf6_add_nexthop(struct list *nh_list, int ifindex, struct in6_addr *addr)
struct ospf6_nexthop nh_match;
if (nh_list) {
- nh_match.ifindex = ifindex;
- if (addr != NULL)
+ if (addr) {
+ if (ifindex)
+ nh_match.type = NEXTHOP_TYPE_IPV6_IFINDEX;
+ else
+ nh_match.type = NEXTHOP_TYPE_IPV6;
+
memcpy(&nh_match.address, addr,
sizeof(struct in6_addr));
- else
+ } else {
+ nh_match.type = NEXTHOP_TYPE_IFINDEX;
+
memset(&nh_match.address, 0, sizeof(struct in6_addr));
+ }
+
+ nh_match.ifindex = ifindex;
if (!ospf6_route_find_nexthop(nh_list, &nh_match)) {
nh = ospf6_nexthop_create();
@@ -299,36 +308,76 @@ void ospf6_add_nexthop(struct list *nh_list, int ifindex, struct in6_addr *addr)
}
}
+void ospf6_add_route_nexthop_blackhole(struct ospf6_route *route)
+{
+ struct ospf6_nexthop *nh;
+ struct ospf6_nexthop nh_match = {};
+
+ /* List not allocated. */
+ if (route->nh_list == NULL)
+ return;
+
+ /* Entry already exists. */
+ nh_match.type = NEXTHOP_TYPE_BLACKHOLE;
+ if (ospf6_route_find_nexthop(route->nh_list, &nh_match))
+ return;
+
+ nh = ospf6_nexthop_create();
+ ospf6_nexthop_copy(nh, &nh_match);
+ listnode_add(route->nh_list, nh);
+}
+
void ospf6_route_zebra_copy_nexthops(struct ospf6_route *route,
struct zapi_nexthop nexthops[],
int entries, vrf_id_t vrf_id)
{
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)) {
- const char *ifname;
- inet_ntop(AF_INET6, &nh->address, buf,
- sizeof(buf));
- ifname = ifindex2ifname(nh->ifindex, vrf_id);
- zlog_debug(" nexthop: %s%%%.*s(%d)", buf,
- IFNAMSIZ, ifname, nh->ifindex);
+ zlog_debug(" nexthop: %s %pI6%%%.*s(%d)",
+ nexthop_type_to_str(nh->type),
+ &nh->address, IFNAMSIZ,
+ ifindex2ifname(nh->ifindex, vrf_id),
+ nh->ifindex);
}
+
if (i >= entries)
return;
nexthops[i].vrf_id = vrf_id;
- nexthops[i].ifindex = nh->ifindex;
- if (!IN6_IS_ADDR_UNSPECIFIED(&nh->address)) {
+ nexthops[i].type = nh->type;
+
+ switch (nh->type) {
+ case NEXTHOP_TYPE_BLACKHOLE:
+ /* NOTHING */
+ break;
+
+ case NEXTHOP_TYPE_IFINDEX:
+ nexthops[i].ifindex = nh->ifindex;
+ break;
+
+ case NEXTHOP_TYPE_IPV4_IFINDEX:
+ case NEXTHOP_TYPE_IPV4:
+ /*
+ * OSPFv3 with IPv4 routes is not supported
+ * yet. Skip this next hop.
+ */
+ if (IS_OSPF6_DEBUG_ZEBRA(SEND))
+ zlog_debug(" Skipping IPv4 next hop");
+ continue;
+
+ case NEXTHOP_TYPE_IPV6_IFINDEX:
+ nexthops[i].ifindex = nh->ifindex;
+ /* FALLTHROUGH */
+ case NEXTHOP_TYPE_IPV6:
nexthops[i].gate.ipv6 = nh->address;
- nexthops[i].type = NEXTHOP_TYPE_IPV6_IFINDEX;
- } else
- nexthops[i].type = NEXTHOP_TYPE_IFINDEX;
+ break;
+ }
i++;
}
}
@@ -404,7 +453,7 @@ void ospf6_copy_paths(struct list *dst, struct list *src)
}
}
-struct ospf6_route *ospf6_route_create(void)
+struct ospf6_route *ospf6_route_create(struct ospf6 *ospf6)
{
struct ospf6_route *route;
@@ -415,6 +464,8 @@ struct ospf6_route *ospf6_route_create(void)
route->paths = list_new();
route->paths->cmp = (int (*)(void *, void *))ospf6_path_cmp;
route->paths->del = (void (*)(void *))ospf6_path_free;
+ route->ospf6 = ospf6;
+
return route;
}
@@ -433,9 +484,10 @@ struct ospf6_route *ospf6_route_copy(struct ospf6_route *route)
{
struct ospf6_route *new;
- new = ospf6_route_create();
+ new = ospf6_route_create(route->ospf6);
new->type = route->type;
memcpy(&new->prefix, &route->prefix, sizeof(struct prefix));
+ new->prefix_options = route->prefix_options;
new->installed = route->installed;
new->changed = route->changed;
new->flag = route->flag;
@@ -1137,6 +1189,7 @@ void ospf6_route_show_detail(struct vty *vty, struct ospf6_route *route,
{
char destination[PREFIX2STR_BUFFER], nexthop[64];
char area_id[16], id[16], adv_router[16], capa[16], options[16];
+ char pfx_options[16];
struct timeval now, res;
char duration[64];
struct listnode *node;
@@ -1264,10 +1317,13 @@ void ospf6_route_show_detail(struct vty *vty, struct ospf6_route *route,
vty_out(vty, "Router Bits: %s\n", capa);
/* Prefix Options */
+ ospf6_prefix_options_printbuf(route->prefix_options, pfx_options,
+ sizeof(pfx_options));
if (use_json)
- json_object_string_add(json_route, "prefixOptions", "xxx");
+ json_object_string_add(json_route, "prefixOptions",
+ pfx_options);
else
- vty_out(vty, "Prefix Options: xxx\n");
+ vty_out(vty, "Prefix Options: %s\n", pfx_options);
/* Metrics */
if (use_json) {
diff --git a/ospf6d/ospf6_route.h b/ospf6d/ospf6_route.h
index a791a82cd4..991720ec2e 100644
--- a/ospf6d/ospf6_route.h
+++ b/ospf6d/ospf6_route.h
@@ -24,6 +24,7 @@
#include "command.h"
#include "zclient.h"
#include "lib/json.h"
+#include "lib/nexthop.h"
#define OSPF6_MULTI_PATH_LIMIT 4
@@ -44,23 +45,60 @@ struct ospf6_nexthop {
/* IP address, if any */
struct in6_addr address;
+
+ /** Next-hop type information. */
+ enum nexthop_types_t type;
};
-#define ospf6_nexthop_is_set(x) \
- ((x)->ifindex || !IN6_IS_ADDR_UNSPECIFIED(&(x)->address))
-#define ospf6_nexthop_is_same(a, b) \
- ((a)->ifindex == (b)->ifindex \
- && IN6_ARE_ADDR_EQUAL(&(a)->address, &(b)->address))
-#define ospf6_nexthop_clear(x) \
- do { \
- (x)->ifindex = 0; \
- memset(&(x)->address, 0, sizeof(struct in6_addr)); \
- } while (0)
-#define ospf6_nexthop_copy(a, b) \
- do { \
- (a)->ifindex = (b)->ifindex; \
- memcpy(&(a)->address, &(b)->address, sizeof(struct in6_addr)); \
- } while (0)
+static inline bool ospf6_nexthop_is_set(const struct ospf6_nexthop *nh)
+{
+ return nh->type != 0;
+}
+
+static inline bool ospf6_nexthop_is_same(const struct ospf6_nexthop *nha,
+ const struct ospf6_nexthop *nhb)
+{
+ if (nha->type != nhb->type)
+ return false;
+
+ switch (nha->type) {
+ case NEXTHOP_TYPE_BLACKHOLE:
+ /* NOTHING */
+ break;
+
+ case NEXTHOP_TYPE_IFINDEX:
+ if (nha->ifindex != nhb->ifindex)
+ return false;
+ break;
+
+ case NEXTHOP_TYPE_IPV4_IFINDEX:
+ case NEXTHOP_TYPE_IPV4:
+ /* OSPFv3 does not support IPv4 next hops. */
+ return false;
+
+ case NEXTHOP_TYPE_IPV6_IFINDEX:
+ if (nha->ifindex != nhb->ifindex)
+ return false;
+ /* FALLTHROUGH */
+ case NEXTHOP_TYPE_IPV6:
+ if (!IN6_ARE_ADDR_EQUAL(&nha->address, &nhb->address))
+ return false;
+ break;
+ }
+
+ return true;
+}
+
+static inline void ospf6_nexthop_clear(struct ospf6_nexthop *nh)
+{
+ memset(nh, 0, sizeof(*nh));
+}
+
+static inline void ospf6_nexthop_copy(struct ospf6_nexthop *nha,
+ const struct ospf6_nexthop *nhb)
+{
+ memcpy(nha, nhb, sizeof(*nha));
+}
/* Path */
struct ospf6_ls_origin {
@@ -79,9 +117,6 @@ struct ospf6_path {
/* Optional Capabilities */
uint8_t options[3];
- /* Prefix Options */
- uint8_t prefix_options;
-
/* Associated Area */
in_addr_t area_id;
@@ -127,6 +162,9 @@ struct ospf6_route {
struct ospf6_route *prev;
struct ospf6_route *next;
+ /* Back pointer to ospf6 */
+ struct ospf6 *ospf6;
+
unsigned int lock;
/* Destination Type */
@@ -147,6 +185,9 @@ struct ospf6_route {
/* flag */
uint8_t flag;
+ /* Prefix Options */
+ uint8_t prefix_options;
+
/* route option */
void *route_option;
@@ -161,6 +202,12 @@ struct ospf6_route {
/* nexthop */
struct list *nh_list;
+
+ /* points to the summarised route */
+ struct ospf6_external_aggr_rt *aggr_route;
+
+ /* For Aggr routes */
+ bool to_be_processed;
};
#define OSPF6_DEST_TYPE_NONE 0
@@ -279,6 +326,7 @@ 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 void ospf6_add_route_nexthop_blackhole(struct ospf6_route *route);
extern int ospf6_num_nexthops(struct list *nh_list);
extern int ospf6_route_cmp_nexthops(struct ospf6_route *a,
struct ospf6_route *b);
@@ -294,7 +342,7 @@ extern int ospf6_route_get_first_nh_index(struct ospf6_route *route);
#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 struct ospf6_route *ospf6_route_create(struct ospf6 *ospf6);
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);
diff --git a/ospf6d/ospf6_spf.c b/ospf6d/ospf6_spf.c
index 032484e288..4e7a7146eb 100644
--- a/ospf6d/ospf6_spf.c
+++ b/ospf6d/ospf6_spf.c
@@ -225,21 +225,25 @@ static char *ospf6_lsdesc_backlink(struct ospf6_lsa *lsa, caddr_t lsdesc,
assert(!(OSPF6_LSA_IS_TYPE(NETWORK, lsa)
&& VERTEX_IS_TYPE(NETWORK, v)));
- if (OSPF6_LSA_IS_TYPE(NETWORK, lsa)
- && NETWORK_LSDESC_GET_NBR_ROUTERID(backlink)
- == v->lsa->header->adv_router)
- found = backlink;
- else if (VERTEX_IS_TYPE(NETWORK, v)
- && ROUTER_LSDESC_IS_TYPE(TRANSIT_NETWORK, backlink)
- && ROUTER_LSDESC_GET_NBR_ROUTERID(backlink)
- == v->lsa->header->adv_router
- && ROUTER_LSDESC_GET_NBR_IFID(backlink)
- == ntohl(v->lsa->header->id))
- found = backlink;
- else {
+ if (OSPF6_LSA_IS_TYPE(NETWORK, lsa)) {
+ if (NETWORK_LSDESC_GET_NBR_ROUTERID(backlink)
+ == v->lsa->header->adv_router)
+ found = backlink;
+ } else if (VERTEX_IS_TYPE(NETWORK, v)) {
+ if (ROUTER_LSDESC_IS_TYPE(TRANSIT_NETWORK, backlink)
+ && ROUTER_LSDESC_GET_NBR_ROUTERID(backlink)
+ == v->lsa->header->adv_router
+ && ROUTER_LSDESC_GET_NBR_IFID(backlink)
+ == ntohl(v->lsa->header->id))
+ found = backlink;
+ } else {
+ assert(OSPF6_LSA_IS_TYPE(ROUTER, lsa)
+ && VERTEX_IS_TYPE(ROUTER, v));
+
if (!ROUTER_LSDESC_IS_TYPE(POINTTOPOINT, backlink)
|| !ROUTER_LSDESC_IS_TYPE(POINTTOPOINT, lsdesc))
continue;
+
if (ROUTER_LSDESC_GET_NBR_IFID(backlink)
!= ROUTER_LSDESC_GET_IFID(lsdesc)
|| ROUTER_LSDESC_GET_NBR_IFID(lsdesc)
@@ -370,7 +374,7 @@ static int ospf6_spf_install(struct ospf6_vertex *v,
up to here. */
assert(route == NULL);
- route = ospf6_route_create();
+ route = ospf6_route_create(v->area->ospf6);
memcpy(&route->prefix, &v->vertex_id, sizeof(struct prefix));
route->type = OSPF6_DEST_TYPE_LINKSTATE;
route->path.type = OSPF6_PATH_TYPE_INTRA;
diff --git a/ospf6d/ospf6_top.c b/ospf6d/ospf6_top.c
index 057f89797a..6105e2c24b 100644
--- a/ospf6d/ospf6_top.c
+++ b/ospf6d/ospf6_top.c
@@ -409,13 +409,31 @@ static struct ospf6 *ospf6_create(const char *name)
o->external_table = OSPF6_ROUTE_TABLE_CREATE(GLOBAL, EXTERNAL_ROUTES);
o->external_table->scope = o;
-
+ /* Setting this to 1, so that the LS ID 0 can be considered as invalid
+ * for self originated external LSAs. This helps in differentiating if
+ * an LSA is originated for any route or not in the route data.
+ * rt->route_option->id is by default 0
+ * Consider a route having id as 0 and prefix as 1::1, an external LSA
+ * is originated with ID 0.0.0.0. Now consider another route 2::2
+ * and for this LSA was not originated because of some configuration
+ * but the ID field rt->route_option->id is still 0.Consider now this
+ * 2::2 is being deleted, it will search LSA with LS ID as 0 and it
+ * will find the LSA and hence delete it but the LSA belonged to prefix
+ * 1::1, this happened because of LS ID 0.
+ */
+ o->external_id = OSPF6_EXT_INIT_LS_ID;
o->external_id_table = route_table_init();
o->write_oi_count = OSPF6_WRITE_INTERFACE_COUNT_DEFAULT;
o->ref_bandwidth = OSPF6_REFERENCE_BANDWIDTH;
o->distance_table = route_table_init();
+
+ o->rt_aggr_tbl = route_table_init();
+ o->aggr_delay_interval = OSPF6_EXTL_AGGR_DEFAULT_DELAY;
+ o->t_external_aggr = NULL;
+ o->aggr_action = OSPF6_ROUTE_AGGR_NONE;
+
o->fd = -1;
o->max_multipath = MULTIPATH_NUM;
@@ -461,6 +479,7 @@ struct ospf6 *ospf6_instance_create(const char *name)
void ospf6_delete(struct ospf6 *o)
{
struct listnode *node, *nnode;
+ struct route_node *rn = NULL;
struct ospf6_area *oa;
struct vrf *vrf;
@@ -499,6 +518,11 @@ void ospf6_delete(struct ospf6 *o)
ospf6_vrf_unlink(o, vrf);
}
+ for (rn = route_top(o->rt_aggr_tbl); rn; rn = route_next(rn))
+ if (rn->info)
+ ospf6_external_aggregator_free(rn->info);
+ route_table_finish(o->rt_aggr_tbl);
+
XFREE(MTYPE_OSPF6_TOP, o->name);
XFREE(MTYPE_OSPF6_TOP, o);
}
@@ -527,6 +551,7 @@ static void ospf6_disable(struct ospf6 *o)
THREAD_OFF(o->t_ase_calc);
THREAD_OFF(o->t_distribute_update);
THREAD_OFF(o->t_ospf6_receive);
+ THREAD_OFF(o->t_external_aggr);
}
}
@@ -602,7 +627,7 @@ void ospf6_router_id_update(struct ospf6 *ospf6)
if (ospf6->router_id_static != 0)
ospf6->router_id = ospf6->router_id_static;
else
- ospf6->router_id = om6->zebra_router_id;
+ ospf6->router_id = ospf6->router_id_zebra;
}
/* start ospf6 */
@@ -690,6 +715,7 @@ static void ospf6_process_reset(struct ospf6 *ospf6)
struct interface *ifp;
struct vrf *vrf = vrf_lookup_by_id(ospf6->vrf_id);
+ ospf6_unset_all_aggr_flag(ospf6);
ospf6_flush_self_originated_lsas_now(ospf6);
ospf6->inst_shutdown = 0;
ospf6_db_clear(ospf6);
@@ -786,8 +812,8 @@ DEFUN(no_ospf6_router_id,
}
}
o->router_id = 0;
- if (o->router_id_zebra.s_addr)
- o->router_id = (uint32_t)o->router_id_zebra.s_addr;
+ if (o->router_id_zebra)
+ o->router_id = o->router_id_zebra;
return CMD_SUCCESS;
}
@@ -989,7 +1015,6 @@ DEFUN_HIDDEN (ospf6_interface_area,
struct ospf6_interface *oi;
struct interface *ifp;
vrf_id_t vrf_id = VRF_DEFAULT;
- int ipv6_count = 0;
uint32_t area_id;
int format;
@@ -1012,23 +1037,6 @@ DEFUN_HIDDEN (ospf6_interface_area,
return CMD_SUCCESS;
}
- /* if more than OSPF6_MAX_IF_ADDRS are configured on this interface
- * then don't allow ospfv3 to be configured
- */
- ipv6_count = connected_count_by_family(ifp, AF_INET6);
- if (oi->ifmtu == OSPF6_DEFAULT_MTU && ipv6_count > OSPF6_MAX_IF_ADDRS) {
- vty_out(vty,
- "can not configure OSPFv3 on if %s, must have less than %d interface addresses but has %d addresses\n",
- ifp->name, OSPF6_MAX_IF_ADDRS, ipv6_count);
- return CMD_WARNING_CONFIG_FAILED;
- } else if (oi->ifmtu >= OSPF6_JUMBO_MTU
- && ipv6_count > OSPF6_MAX_IF_ADDRS_JUMBO) {
- vty_out(vty,
- "can not configure OSPFv3 on if %s, must have less than %d interface addresses but has %d addresses\n",
- ifp->name, OSPF6_MAX_IF_ADDRS_JUMBO, ipv6_count);
- return CMD_WARNING_CONFIG_FAILED;
- }
-
if (str2area_id(argv[idx_ipv4]->arg, &area_id, &format)) {
vty_out(vty, "Malformed Area-ID: %s\n", argv[idx_ipv4]->arg);
return CMD_WARNING_CONFIG_FAILED;
@@ -1672,6 +1680,424 @@ DEFUN(show_ipv6_ospf6_route_type_detail, show_ipv6_ospf6_route_type_detail_cmd,
return CMD_SUCCESS;
}
+bool ospf6_is_valid_summary_addr(struct vty *vty, struct prefix *p)
+{
+ struct in6_addr addr_zero;
+
+ memset(&addr_zero, 0, sizeof(struct in6_addr));
+
+ /* Default prefix validation*/
+ if ((is_default_prefix((struct prefix *)p))
+ || (!memcmp(&p->u.prefix6, &addr_zero, sizeof(struct in6_addr)))) {
+ vty_out(vty, "Default address should not be configured as summary address.\n");
+ return false;
+ }
+
+ /* Host route should not be configured as summary address */
+ if (p->prefixlen == IPV6_MAX_BITLEN) {
+ vty_out(vty, "Host route should not be configured as summary address.\n");
+ return false;
+ }
+
+ return true;
+}
+
+/* External Route Aggregation */
+DEFPY (ospf6_external_route_aggregation,
+ ospf6_external_route_aggregation_cmd,
+ "summary-address X:X::X:X/M$prefix [tag (1-4294967295)] [{metric (0-16777215) | metric-type (1-2)$mtype}]",
+ "External summary address\n"
+ "Specify IPv6 prefix\n"
+ "Router tag \n"
+ "Router tag value\n"
+ "Metric \n"
+ "Advertised metric for this route\n"
+ "OSPFv3 exterior metric type for summarised routes\n"
+ "Set OSPFv3 External Type 1/2 metrics\n")
+{
+ VTY_DECLVAR_CONTEXT(ospf6, ospf6);
+
+ struct prefix p;
+ int ret = CMD_SUCCESS;
+
+ p.family = AF_INET6;
+ ret = str2prefix(prefix_str, &p);
+ if (ret == 0) {
+ vty_out(vty, "Malformed prefix\n");
+ return CMD_WARNING_CONFIG_FAILED;
+ }
+
+ /* Apply mask for given prefix. */
+ apply_mask((struct prefix *)&p);
+
+ if (!ospf6_is_valid_summary_addr(vty, &p))
+ return CMD_WARNING_CONFIG_FAILED;
+
+ if (!tag_str)
+ tag = 0;
+
+ if (!metric_str)
+ metric = -1;
+
+ if (!mtype_str)
+ mtype = DEFAULT_METRIC_TYPE;
+
+ ret = ospf6_external_aggr_config_set(ospf6, &p, tag, metric, mtype);
+ if (ret == OSPF6_FAILURE) {
+ vty_out(vty, "Invalid configuration!!\n");
+ return CMD_WARNING_CONFIG_FAILED;
+ }
+
+ return CMD_SUCCESS;
+}
+
+DEFPY(no_ospf6_external_route_aggregation,
+ no_ospf6_external_route_aggregation_cmd,
+ "no summary-address X:X::X:X/M$prefix [tag (1-4294967295)] [{metric (0-16777215) | metric-type (1-2)}]",
+ NO_STR
+ "External summary address\n"
+ "Specify IPv6 prefix\n"
+ "Router tag\n"
+ "Router tag value\n"
+ "Metric \n"
+ "Advertised metric for this route\n"
+ "OSPFv3 exterior metric type for summarised routes\n"
+ "Set OSPFv3 External Type 1/2 metrics\n")
+{
+ VTY_DECLVAR_CONTEXT(ospf6, ospf6);
+
+ struct prefix p;
+ int ret = CMD_SUCCESS;
+
+ ret = str2prefix(prefix_str, &p);
+ if (ret == 0) {
+ vty_out(vty, "Malformed prefix\n");
+ return CMD_WARNING_CONFIG_FAILED;
+ }
+
+ /* Apply mask for given prefix. */
+ apply_mask((struct prefix *)&p);
+
+ if (!ospf6_is_valid_summary_addr(vty, &p))
+ return CMD_WARNING_CONFIG_FAILED;
+
+ ret = ospf6_external_aggr_config_unset(ospf6, &p);
+ if (ret == OSPF6_INVALID)
+ vty_out(vty, "Invalid configuration!!\n");
+
+ return CMD_SUCCESS;
+}
+
+DEFPY (ospf6_external_route_aggregation_no_advertise,
+ ospf6_external_route_aggregation_no_advertise_cmd,
+ "summary-address X:X::X:X/M$prefix no-advertise",
+ "External summary address\n"
+ "Specify IPv6 prefix\n"
+ "Don't advertise summary route \n")
+{
+ VTY_DECLVAR_CONTEXT(ospf6, ospf6);
+
+ struct prefix p;
+ int ret = CMD_SUCCESS;
+
+ ret = str2prefix(prefix_str, &p);
+ if (ret == 0) {
+ vty_out(vty, "Malformed prefix\n");
+ return CMD_WARNING_CONFIG_FAILED;
+ }
+
+ /* Apply mask for given prefix. */
+ apply_mask((struct prefix *)&p);
+
+ if (!ospf6_is_valid_summary_addr(vty, &p))
+ return CMD_WARNING_CONFIG_FAILED;
+
+ ret = ospf6_asbr_external_rt_no_advertise(ospf6, &p);
+ if (ret == OSPF6_INVALID)
+ vty_out(vty, "!!Invalid configuration\n");
+
+ return CMD_SUCCESS;
+}
+
+DEFPY (no_ospf6_external_route_aggregation_no_advertise,
+ no_ospf6_external_route_aggregation_no_advertise_cmd,
+ "no summary-address X:X::X:X/M$prefix no-advertise",
+ NO_STR
+ "External summary address\n"
+ "Specify IPv6 prefix\n"
+ "Adverise summary route to the AS \n")
+{
+ VTY_DECLVAR_CONTEXT(ospf6, ospf6);
+
+ struct prefix p;
+ int ret = CMD_SUCCESS;
+
+ ret = str2prefix(prefix_str, &p);
+ if (ret == 0) {
+ vty_out(vty, "Malformed prefix\n");
+ return CMD_WARNING_CONFIG_FAILED;
+ }
+
+ /* Apply mask for given prefix. */
+ apply_mask((struct prefix *)&p);
+
+ if (!ospf6_is_valid_summary_addr(vty, &p))
+ return CMD_WARNING_CONFIG_FAILED;
+
+ ret = ospf6_asbr_external_rt_advertise(ospf6, &p);
+ if (ret == OSPF6_INVALID)
+ vty_out(vty, "!!Invalid configuration\n");
+
+ return CMD_SUCCESS;
+}
+
+DEFPY (ospf6_route_aggregation_timer,
+ ospf6_route_aggregation_timer_cmd,
+ "aggregation timer (5-1800)",
+ "External route aggregation\n"
+ "Delay timer (in seconds)\n"
+ "Timer interval(in seconds)\n")
+{
+ VTY_DECLVAR_CONTEXT(ospf6, ospf6);
+
+ ospf6_external_aggr_delay_timer_set(ospf6, timer);
+
+ return CMD_SUCCESS;
+}
+
+DEFPY (no_ospf6_route_aggregation_timer,
+ no_ospf6_route_aggregation_timer_cmd,
+ "no aggregation timer [5-1800]",
+ NO_STR
+ "External route aggregation\n"
+ "Delay timer\n"
+ "Timer interval(in seconds)\n")
+{
+ VTY_DECLVAR_CONTEXT(ospf6, ospf6);
+
+ ospf6_external_aggr_delay_timer_set(ospf6,
+ OSPF6_EXTL_AGGR_DEFAULT_DELAY);
+ return CMD_SUCCESS;
+}
+
+static int
+ospf6_print_vty_external_routes_walkcb(struct hash_bucket *bucket, void *arg)
+{
+ struct ospf6_route *rt = bucket->data;
+ struct vty *vty = (struct vty *)arg;
+ static unsigned int count;
+
+ vty_out(vty, "%pFX ", &rt->prefix);
+
+ count++;
+
+ if (count%5 == 0)
+ vty_out(vty, "\n");
+
+ if (OSPF6_EXTERNAL_RT_COUNT(rt->aggr_route) == count)
+ count = 0;
+
+ return HASHWALK_CONTINUE;
+}
+
+static int
+ospf6_print_json_external_routes_walkcb(struct hash_bucket *bucket, void *arg)
+{
+ struct ospf6_route *rt = bucket->data;
+ struct json_object *json = (struct json_object *)arg;
+ char buf[PREFIX2STR_BUFFER];
+ char exnalbuf[20];
+ static unsigned int count;
+
+ prefix2str(&rt->prefix, buf, sizeof(buf));
+
+ snprintf(exnalbuf, sizeof(exnalbuf), "Exnl Addr-%d", count);
+
+ json_object_string_add(json, exnalbuf, buf);
+
+ count++;
+
+ if (OSPF6_EXTERNAL_RT_COUNT(rt->aggr_route) == count)
+ count = 0;
+
+ return HASHWALK_CONTINUE;
+}
+
+static void
+ospf6_show_vrf_name(struct vty *vty, struct ospf6 *ospf6,
+ json_object *json)
+{
+ if (json) {
+ if (ospf6->vrf_id == VRF_DEFAULT)
+ json_object_string_add(json, "vrfName",
+ "default");
+ else
+ json_object_string_add(json, "vrfName",
+ ospf6->name);
+ json_object_int_add(json, "vrfId", ospf6->vrf_id);
+ } else {
+ if (ospf6->vrf_id == VRF_DEFAULT)
+ vty_out(vty, "VRF Name: %s\n", "default");
+ else if (ospf6->name)
+ vty_out(vty, "VRF Name: %s\n", ospf6->name);
+ }
+}
+
+static int
+ospf6_show_summary_address(struct vty *vty, struct ospf6 *ospf6,
+ json_object *json,
+ bool uj, const char *detail)
+{
+ struct route_node *rn;
+ static const char header[] = "Summary-address Metric-type Metric Tag External_Rt_count\n";
+ json_object *json_vrf = NULL;
+
+ if (!uj) {
+ ospf6_show_vrf_name(vty, ospf6, json_vrf);
+ vty_out(vty, "aggregation delay interval :%d(in seconds)\n\n",
+ ospf6->aggr_delay_interval);
+ vty_out(vty, "%s\n", header);
+ } else {
+ json_vrf = json_object_new_object();
+
+ ospf6_show_vrf_name(vty, ospf6, json_vrf);
+
+ json_object_int_add(json_vrf, "aggregation delay interval",
+ ospf6->aggr_delay_interval);
+ }
+
+
+ for (rn = route_top(ospf6->rt_aggr_tbl); rn; rn = route_next(rn)) {
+ if (!rn->info)
+ continue;
+
+ struct ospf6_external_aggr_rt *aggr = rn->info;
+ json_object *json_aggr = NULL;
+ char buf[PREFIX2STR_BUFFER];
+
+ prefix2str(&aggr->p, buf, sizeof(buf));
+
+ if (uj) {
+
+ json_aggr = json_object_new_object();
+
+ json_object_object_add(json_vrf,
+ buf,
+ json_aggr);
+
+ json_object_string_add(json_aggr,
+ "Summary address",
+ buf);
+
+ json_object_string_add(
+ json_aggr, "Metric-type",
+ (aggr->mtype == DEFAULT_METRIC_TYPE)
+ ? "E2"
+ : "E1");
+
+ json_object_int_add(json_aggr, "Metric",
+ (aggr->metric != -1)
+ ? aggr->metric
+ : DEFAULT_DEFAULT_METRIC);
+
+ json_object_int_add(json_aggr, "Tag",
+ aggr->tag);
+
+ json_object_int_add(json_aggr,
+ "External route count",
+ OSPF6_EXTERNAL_RT_COUNT(aggr));
+
+ if (OSPF6_EXTERNAL_RT_COUNT(aggr) && detail) {
+ json_object_int_add(json_aggr, "ID",
+ aggr->id);
+ json_object_int_add(json_aggr, "Flags",
+ aggr->aggrflags);
+ hash_walk(aggr->match_extnl_hash,
+ ospf6_print_json_external_routes_walkcb,
+ json_aggr);
+ }
+
+ } else {
+ vty_out(vty, "%-22s", buf);
+
+ (aggr->mtype == DEFAULT_METRIC_TYPE)
+ ? vty_out(vty, "%-16s", "E2")
+ : vty_out(vty, "%-16s", "E1");
+ vty_out(vty, "%-11d", (aggr->metric != -1)
+ ? aggr->metric
+ : DEFAULT_DEFAULT_METRIC);
+
+ vty_out(vty, "%-12u", aggr->tag);
+
+ vty_out(vty, "%-5ld\n",
+ OSPF6_EXTERNAL_RT_COUNT(aggr));
+
+ if (OSPF6_EXTERNAL_RT_COUNT(aggr) && detail) {
+ vty_out(vty,
+ "Matched External routes:\n");
+ hash_walk(aggr->match_extnl_hash,
+ ospf6_print_vty_external_routes_walkcb,
+ vty);
+ vty_out(vty, "\n");
+ }
+
+ vty_out(vty, "\n");
+ }
+ }
+
+ if (uj)
+ json_object_object_add(json, ospf6->name,
+ json_vrf);
+
+ return CMD_SUCCESS;
+}
+
+DEFPY (show_ipv6_ospf6_external_aggregator,
+ show_ipv6_ospf6_external_aggregator_cmd,
+ "show ipv6 ospf6 [vrf <NAME|all>] summary-address [detail$detail] [json]",
+ SHOW_STR
+ IP6_STR
+ OSPF6_STR
+ VRF_CMD_HELP_STR
+ "All VRFs\n"
+ "Show external summary addresses\n"
+ "detailed informtion\n"
+ JSON_STR)
+{
+ bool uj = use_json(argc, argv);
+ struct ospf6 *ospf6 = NULL;
+ json_object *json = NULL;
+ const char *vrf_name = NULL;
+ struct listnode *node;
+ bool all_vrf = false;
+ int idx_vrf = 0;
+
+ if (uj)
+ json = json_object_new_object();
+
+ OSPF6_CMD_CHECK_RUNNING();
+ OSPF6_FIND_VRF_ARGS(argv, argc, idx_vrf, vrf_name, all_vrf);
+
+ for (ALL_LIST_ELEMENTS_RO(om6->ospf6, node, ospf6)) {
+ if (all_vrf || strcmp(ospf6->name, vrf_name) == 0) {
+
+ ospf6_show_summary_address(vty, ospf6, json, uj,
+ detail);
+
+ if (!all_vrf)
+ break;
+ }
+ }
+
+ if (uj) {
+ vty_out(vty, "%s\n", json_object_to_json_string_ext(
+ json, JSON_C_TO_STRING_PRETTY));
+ json_object_free(json);
+ }
+
+ return CMD_SUCCESS;
+}
+
static void ospf6_stub_router_config_write(struct vty *vty, struct ospf6 *ospf6)
{
if (CHECK_FLAG(ospf6->flag, OSPF6_STUB_ROUTER)) {
@@ -1711,6 +2137,44 @@ static int ospf6_distance_config_write(struct vty *vty, struct ospf6 *ospf6)
return 0;
}
+static int ospf6_asbr_summary_config_write(struct vty *vty, struct ospf6 *ospf6)
+{
+ struct route_node *rn;
+ struct ospf6_external_aggr_rt *aggr;
+ char buf[PREFIX2STR_BUFFER];
+
+ if (ospf6->aggr_delay_interval != OSPF6_EXTL_AGGR_DEFAULT_DELAY)
+ vty_out(vty, " aggregation timer %u\n",
+ ospf6->aggr_delay_interval);
+
+ /* print 'summary-address A:B::C:D/M' */
+ for (rn = route_top(ospf6->rt_aggr_tbl); rn; rn = route_next(rn)) {
+ if (!rn->info)
+ continue;
+
+ aggr = rn->info;
+
+ prefix2str(&aggr->p, buf, sizeof(buf));
+ vty_out(vty, " summary-address %s", buf);
+ if (aggr->tag)
+ vty_out(vty, " tag %u", aggr->tag);
+
+ if (aggr->metric != -1)
+ vty_out(vty, " metric %d", aggr->metric);
+
+ if (aggr->mtype != DEFAULT_METRIC_TYPE)
+ vty_out(vty, " metric-type %d", aggr->mtype);
+
+ if (CHECK_FLAG(aggr->aggrflags,
+ OSPF6_EXTERNAL_AGGRT_NO_ADVERTISE))
+ vty_out(vty, " no-advertise");
+
+ vty_out(vty, "\n");
+ }
+
+ return 0;
+}
+
/* OSPF configuration write function. */
static int config_write_ospf6(struct vty *vty)
{
@@ -1768,6 +2232,7 @@ static int config_write_ospf6(struct vty *vty)
ospf6_spf_config_write(vty, ospf6);
ospf6_distance_config_write(vty, ospf6);
ospf6_distribute_config_write(vty, ospf6);
+ ospf6_asbr_summary_config_write(vty, ospf6);
vty_out(vty, "!\n");
}
@@ -1826,6 +2291,17 @@ void ospf6_top_init(void)
install_element(OSPF6_NODE, &ospf6_max_multipath_cmd);
install_element(OSPF6_NODE, &no_ospf6_max_multipath_cmd);
+ /* ASBR Summarisation */
+ install_element(OSPF6_NODE, &ospf6_external_route_aggregation_cmd);
+ install_element(OSPF6_NODE, &no_ospf6_external_route_aggregation_cmd);
+ install_element(OSPF6_NODE,
+ &ospf6_external_route_aggregation_no_advertise_cmd);
+ install_element(OSPF6_NODE,
+ &no_ospf6_external_route_aggregation_no_advertise_cmd);
+ install_element(OSPF6_NODE, &ospf6_route_aggregation_timer_cmd);
+ install_element(OSPF6_NODE, &no_ospf6_route_aggregation_timer_cmd);
+ install_element(VIEW_NODE, &show_ipv6_ospf6_external_aggregator_cmd);
+
install_element(OSPF6_NODE, &ospf6_distance_cmd);
install_element(OSPF6_NODE, &no_ospf6_distance_cmd);
install_element(OSPF6_NODE, &ospf6_distance_ospf6_cmd);
diff --git a/ospf6d/ospf6_top.h b/ospf6d/ospf6_top.h
index 51df4b6b8e..fe02cd3f84 100644
--- a/ospf6d/ospf6_top.h
+++ b/ospf6d/ospf6_top.h
@@ -29,7 +29,6 @@ struct ospf6_master {
struct list *ospf6;
/* OSPFv3 thread master. */
struct thread_master *master;
- in_addr_t zebra_router_id;
};
/* ospf6->config_flags */
@@ -38,9 +37,12 @@ enum {
OSPF6_LOG_ADJACENCY_DETAIL = (1 << 1),
};
+/* For processing route-map change update in the callback */
+#define OSPF6_IS_RMAP_CHANGED 0x01
struct ospf6_redist {
uint8_t instance;
+ uint8_t flag;
/* Redistribute metric info. */
struct {
int type; /* External metric type (E1 or E2). */
@@ -71,7 +73,7 @@ struct ospf6 {
/* static router id */
in_addr_t router_id_static;
- struct in_addr router_id_zebra;
+ in_addr_t router_id_zebra;
/* start time */
struct timeval starttime;
@@ -89,6 +91,7 @@ struct ospf6 {
struct ospf6_route_table *external_table;
struct route_table *external_id_table;
+#define OSPF6_EXT_INIT_LS_ID 1
uint32_t external_id;
/* OSPF6 redistribute configuration */
@@ -128,6 +131,7 @@ struct ospf6 {
struct thread *maxage_remover;
struct thread *t_distribute_update; /* Distirbute update timer. */
struct thread *t_ospf6_receive; /* OSPF6 receive timer */
+ struct thread *t_external_aggr; /* OSPF6 aggregation timer */
#define OSPF6_WRITE_INTERFACE_COUNT_DEFAULT 20
struct thread *t_write;
@@ -156,16 +160,22 @@ struct ospf6 {
struct list *oi_write_q;
uint32_t redist_count;
+
+ /* Action for aggregation of external LSAs */
+ int aggr_action;
+
+#define OSPF6_EXTL_AGGR_DEFAULT_DELAY 5
+ /* For ASBR summary delay timer */
+ int aggr_delay_interval;
+ /* Table of configured Aggregate addresses */
+ struct route_table *rt_aggr_tbl;
+
QOBJ_FIELDS;
};
DECLARE_QOBJ_TYPE(ospf6);
#define OSPF6_DISABLED 0x01
#define OSPF6_STUB_ROUTER 0x02
-#define OSPF6_MAX_IF_ADDRS 100
-#define OSPF6_MAX_IF_ADDRS_JUMBO 200
-#define OSPF6_DEFAULT_MTU 1500
-#define OSPF6_JUMBO_MTU 9000
/* global pointer for OSPF top data structure */
extern struct ospf6 *ospf6;
@@ -186,4 +196,5 @@ struct ospf6 *ospf6_lookup_by_vrf_id(vrf_id_t vrf_id);
struct ospf6 *ospf6_lookup_by_vrf_name(const char *name);
const char *ospf6_vrf_id_to_name(vrf_id_t vrf_id);
void ospf6_vrf_init(void);
+bool ospf6_is_valid_summary_addr(struct vty *vty, struct prefix *p);
#endif /* OSPF6_TOP_H */
diff --git a/ospf6d/ospf6_zebra.c b/ospf6d/ospf6_zebra.c
index 170d545c49..5403e643dc 100644
--- a/ospf6d/ospf6_zebra.c
+++ b/ospf6d/ospf6_zebra.c
@@ -90,15 +90,16 @@ static int ospf6_router_id_update_zebra(ZAPI_CALLBACK_ARGS)
zebra_router_id_update_read(zclient->ibuf, &router_id);
- om6->zebra_router_id = router_id.u.prefix4.s_addr;
+ if (IS_OSPF6_DEBUG_ZEBRA(RECV))
+ zlog_debug("Zebra router-id update %pI4 vrf %s id %u",
+ &router_id.u.prefix4, ospf6_vrf_id_to_name(vrf_id),
+ vrf_id);
+
o = ospf6_lookup_by_vrf_id(vrf_id);
if (o == NULL)
return 0;
- o->router_id_zebra = router_id.u.prefix4;
- if (IS_OSPF6_DEBUG_ZEBRA(RECV))
- zlog_debug("%s: zebra router-id %pI4 update", __func__,
- &router_id.u.prefix4);
+ o->router_id_zebra = router_id.u.prefix4.s_addr;
ospf6_router_id_update(o);
@@ -130,38 +131,17 @@ void ospf6_zebra_no_redistribute(int type, vrf_id_t vrf_id)
static int ospf6_zebra_if_address_update_add(ZAPI_CALLBACK_ARGS)
{
struct connected *c;
- struct ospf6_interface *oi;
- int ipv6_count = 0;
c = zebra_interface_address_read(ZEBRA_INTERFACE_ADDRESS_ADD,
zclient->ibuf, vrf_id);
if (c == NULL)
return 0;
- oi = (struct ospf6_interface *)c->ifp->info;
- if (oi == NULL)
- oi = ospf6_interface_create(c->ifp);
- assert(oi);
-
if (IS_OSPF6_DEBUG_ZEBRA(RECV))
zlog_debug("Zebra Interface address add: %s %5s %pFX",
c->ifp->name, prefix_family_str(c->address),
c->address);
- ipv6_count = connected_count_by_family(c->ifp, AF_INET6);
- if (oi->ifmtu == OSPF6_DEFAULT_MTU && ipv6_count > OSPF6_MAX_IF_ADDRS) {
- zlog_warn(
- "Zebra Interface : %s has too many interface addresses %d only support %d, increase MTU",
- c->ifp->name, ipv6_count, OSPF6_MAX_IF_ADDRS);
- return 0;
- } else if (oi->ifmtu >= OSPF6_JUMBO_MTU
- && ipv6_count > OSPF6_MAX_IF_ADDRS_JUMBO) {
- zlog_warn(
- "Zebra Interface : %s has too many interface addresses %d only support %d",
- c->ifp->name, ipv6_count, OSPF6_MAX_IF_ADDRS_JUMBO);
- return 0;
- }
-
if (c->address->family == AF_INET6) {
ospf6_interface_state_update(c->ifp);
ospf6_interface_connected_route_update(c->ifp);
@@ -193,16 +173,6 @@ static int ospf6_zebra_if_address_update_delete(ZAPI_CALLBACK_ARGS)
return 0;
}
-static int is_prefix_default(struct prefix_ipv6 *p)
-{
- struct prefix_ipv6 q = {};
-
- q.family = AF_INET6;
- q.prefixlen = 0;
-
- return prefix_same((struct prefix *)p, (struct prefix *)&q);
-}
-
static int ospf6_zebra_read_route(ZAPI_CALLBACK_ARGS)
{
struct zapi_route api;
@@ -238,7 +208,7 @@ static int ospf6_zebra_read_route(ZAPI_CALLBACK_ARGS)
ifindex, api.tag);
memcpy(&p, &api.prefix, sizeof(p));
- if (is_prefix_default(&p))
+ if (is_default_prefix6(&p))
api.type = DEFAULT_ROUTE;
if (cmd == ZEBRA_REDISTRIBUTE_ROUTE_ADD)
diff --git a/ospf6d/ospf6d.h b/ospf6d/ospf6d.h
index e054803df3..5afece9b0a 100644
--- a/ospf6d/ospf6d.h
+++ b/ospf6d/ospf6d.h
@@ -49,6 +49,10 @@ extern struct thread_master *master;
#define MSG_OK 0
#define MSG_NG 1
+#define OSPF6_SUCCESS 1
+#define OSPF6_FAILURE 0
+#define OSPF6_INVALID -1
+
/* cast macro: XXX - these *must* die, ick ick. */
#define OSPF6_PROCESS(x) ((struct ospf6 *) (x))
#define OSPF6_AREA(x) ((struct ospf6_area *) (x))
diff --git a/ospf6d/subdir.am b/ospf6d/subdir.am
index 2b7bce5392..78fb26b00e 100644
--- a/ospf6d/subdir.am
+++ b/ospf6d/subdir.am
@@ -84,12 +84,13 @@ ospf6d_ospf6d_SOURCES = \
ospf6d_ospf6d_snmp_la_SOURCES = ospf6d/ospf6_snmp.c
ospf6d_ospf6d_snmp_la_CFLAGS = $(AM_CFLAGS) $(SNMP_CFLAGS) -std=gnu11
-ospf6d_ospf6d_snmp_la_LDFLAGS = -avoid-version -module -shared -export-dynamic
+ospf6d_ospf6d_snmp_la_LDFLAGS = $(MODULE_LDFLAGS)
ospf6d_ospf6d_snmp_la_LIBADD = lib/libfrrsnmp.la
clippy_scan += \
ospf6d/ospf6_top.c \
ospf6d/ospf6_asbr.c \
+ ospf6d/ospf6_lsa.c \
# end
nodist_ospf6d_ospf6d_SOURCES = \