]> git.proxmox.com Git - mirror_frr.git/commitdiff
Merge pull request #9028 from mobash-rasool/ospfv3-asbr-summarisation
authorRuss White <russ@riw.us>
Fri, 30 Jul 2021 10:37:50 +0000 (06:37 -0400)
committerGitHub <noreply@github.com>
Fri, 30 Jul 2021 10:37:50 +0000 (06:37 -0400)
Ospfv3 ASBR summarisation feature

23 files changed:
doc/user/ospf6d.rst
ospf6d/ospf6_abr.c
ospf6d/ospf6_area.c
ospf6d/ospf6_asbr.c
ospf6d/ospf6_asbr.h
ospf6d/ospf6_flood.c
ospf6d/ospf6_flood.h
ospf6d/ospf6_interface.c
ospf6d/ospf6_intra.c
ospf6d/ospf6_lsa.c
ospf6d/ospf6_lsa.h
ospf6d/ospf6_lsdb.c
ospf6d/ospf6_nssa.c
ospf6d/ospf6_route.c
ospf6d/ospf6_route.h
ospf6d/ospf6_spf.c
ospf6d/ospf6_top.c
ospf6d/ospf6_top.h
ospf6d/ospf6d.h
ospf6d/subdir.am
tests/topotests/lib/ospf.py
tests/topotests/ospfv3_basic_functionality/ospfv3_asbr_summary_topo1.json [new file with mode: 0644]
tests/topotests/ospfv3_basic_functionality/test_ospfv3_asbr_summary_topo1.py [new file with mode: 0644]

index 5344f4cb05274025692f0d2dbbf25e28ccf9394f..f8595ef3f5a983895ca52a82de1b223d7eda1136 100644 (file)
@@ -85,6 +85,83 @@ OSPF6 router
    change to take effect, user can use this cli instead of restarting the
    ospf6d daemon.
 
+ASBR Summarisation Support in OSPFv3
+====================================
+
+   External routes in OSPFv3 are carried by type 5/7 LSA (external LSAs).
+   External LSAs are generated by ASBR (Autonomous System Boundary Router).
+   Large topology database requires a large amount of router memory, which
+   slows down all processes, including SPF calculations.
+   It is necessary to reduce the size of the OSPFv3 topology database,
+   especially in a large network. Summarising routes keeps the routing
+   tables smaller and easier to troubleshoot.
+
+   External route summarization must be configured on ASBR.
+   Stub area do not allow ASBR because they don’t allow type 5 LSAs.
+
+   An ASBR will inject a summary route into the OSPFv3 domain.
+
+   Summary route will only be advertised if you have at least one subnet
+   that falls within the summary range.
+
+   Users will be allowed an option in the CLI to not advertise range of
+   ipv6 prefixes as well.
+
+   The configuration of ASBR Summarisation is supported using the CLI command
+
+.. clicmd:: summary-address X:X::X:X/M [tag (1-4294967295)] [{metric (0-16777215) | metric-type (1-2)}]
+
+   This command will advertise a single External LSA on behalf of all the
+   prefixes falling under this range configured by the CLI.
+   The user is allowed to configure tag, metric and metric-type as well.
+   By default, tag is not configured, default metric as 20 and metric-type
+   as type-2 gets advertised.
+   A summary route is created when one or more specific routes are learned and
+   removed when no more specific route exist.
+   The summary route is also installed in the local system with Null0 as
+   next-hop to avoid leaking traffic.
+
+.. clicmd:: no summary-address X:X::X:X/M [tag (1-4294967295)] [{metric (0-16777215) | metric-type (1-2)}]
+
+   This command can be used to remove the summarisation configuration.
+   This will flush the single External LSA if it was originated and advertise
+   the External LSAs for all the existing individual prefixes.
+
+.. clicmd:: summary-address X:X::X:X/M no-advertise
+
+   This command can be used when user do not want to advertise a certain
+   range of prefixes using the no-advertise option.
+   This command when configured will flush all the existing external LSAs
+   falling under this range.
+
+.. clicmd:: no summary-address X:X::X:X/M no-advertise
+
+   This command can be used to remove the previous configuration.
+   When configured, tt will resume originating external LSAs for all the prefixes
+   falling under the configured range.
+
+.. clicmd:: aggregation timer (5-1800)
+
+   The summarisation command takes effect after the aggregation timer expires.
+   By default the value of this timer is 5 seconds. User can modify the time
+   after which the external LSAs should get originated using this command.
+
+.. clicmd:: no aggregation timer (5-1800)
+
+   This command removes the timer configuration. It reverts back to default
+   5 second timer.
+
+.. clicmd:: show ipv6 ospf6 summary-address [detail] [json]
+
+   This command can be used to see all the summary-address related information.
+   When detail option is used, it shows all the prefixes falling under each
+   summary-configuration apart from other information.
+
+.. clicmd:: debug ospf6 lsa aggregation
+
+   This command can be used to enable the debugs related to the summarisation
+   of these LSAs.
+
 .. _ospf6-debugging:
 
 OSPFv3 Debugging
index 9dd232dae5cea71009efecc55eabece71308b752..69be807c13d913b0345b281bfbd0c98cf2c3f3d2 100644 (file)
@@ -715,7 +715,7 @@ void ospf6_abr_defaults_to_stub(struct ospf6 *o)
        if (!o->backbone)
                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;
@@ -1150,7 +1150,7 @@ 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;
@@ -1237,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);
index 355b8441bd462b4727e976b78054fbb9e132e711..f4d9964a577d84160e41c96b94896a82ce933d63 100644 (file)
@@ -519,7 +519,7 @@ 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;
index 84111e4b7dbcfc53b65a44c07519a4e131273378..165e409eedbeb283f51457eca44b5575abd415be 100644 (file)
@@ -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;
@@ -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)
@@ -583,7 +605,7 @@ 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;
@@ -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;
@@ -1301,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,
@@ -1308,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;
@@ -1378,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));
@@ -1414,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)) {
@@ -1463,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 = IPV4_MAX_BITLEN;
-       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;
-
-       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);
-       }
+       ospf6_handle_external_lsa_origination(ospf6, route, prefix);
 
-       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) {
@@ -1517,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 = IPV4_MAX_BITLEN;
-       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);
@@ -1574,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;
@@ -2613,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);
+       }
+}
index 7ccd1c992b3aaba0e6b03c703bd8ea999c561970..0aa1374a468e964562e2993565c5fe5fc759dd4a 100644 (file)
@@ -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 */
@@ -110,8 +156,31 @@ extern void ospf6_asbr_distribute_list_update(struct ospf6 *ospf6,
 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 */
index 0a384a98e696176e5efc0f6838ad89100fc05ad0..3d52597161766aae744af26ecc132ba199231b0e 100644 (file)
@@ -116,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);
 
@@ -149,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;
index 5515a1c3feac8ada7e0e4571961267c5b9e96e1a..4e4fc55ed4a501efa797c518c948d1b4706aae92 100644 (file)
@@ -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,
index 468a4b8e81d27f351b9b1d0840eebfc578271e45..ec672d8f3f8395600d30f1dc8f318aa82c64f9f9 100644 (file)
@@ -435,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;
index 06f64bbc40d3a9d95f8090512a5b88949d9d6cd7..e4db8f3a026e5cc24e43ee0ce586369a57f52e2a 100644 (file)
@@ -1327,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;
@@ -1790,7 +1790,7 @@ 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;
index bab5fdaae8fefc41b31672af9488f7ce590870a9..9c03ce21ed355cd21079acd49d02a3d514c01d3c 100644 (file)
 #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;
index 15b0d4ebbc8a845258e621075d9f970a858e5be3..4c95ee69bd82bff2631eac9ee61f2895bb0874de 100644 (file)
@@ -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 */
index 304f03fde8a8373783d1b6a4ebbbccbc550fa35e..039c65d7398b7c85a6497b7777477ad23e40db3a 100644 (file)
@@ -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)
index 34d17941f47cb33939b26e9f5606ab13ed8d9bd5..470a5b1338a74b4ee20fbd04fca54562a83d2df1 100644 (file)
@@ -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 */
index 80f0e7d26bf791891b2f2d28577b6b56a8fd2bd8..cd3139d28a54c650463a575f6b95a506a053bc7b 100644 (file)
@@ -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,7 +484,7 @@ 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;
index ecfb45d1ea0d023ed7859ca3b4215630d2ac2cdb..991720ec2e6ed1446cd191209adc45c2d6031db7 100644 (file)
@@ -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 {
@@ -124,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 */
@@ -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);
index 051b3a63efa6ba9879b7d0531658e798cace262c..4e7a7146eb4c131553177d4d89df79c323df21a4 100644 (file)
@@ -374,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;
index 92f1e50c65dd037900d95099cde4a72750991617..6105e2c24be29dca0b17e699205f17e3a3a82ee6 100644 (file)
@@ -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);
        }
 }
 
@@ -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);
@@ -1654,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)) {
@@ -1693,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)
 {
@@ -1750,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");
        }
@@ -1808,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);
index b546ee87ae469c1542991c82442433f416d1b1ca..fe02cd3f84927bfe89812b18f274c4acec017b43 100644 (file)
@@ -91,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 */
@@ -130,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;
 
@@ -158,6 +160,16 @@ 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);
@@ -184,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 */
index e054803df357cc0ca6c9ed7c94852e601e18b1ef..5afece9b0a859352761f2a56d1a27081616b719d 100644 (file)
@@ -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))
index 3f9ff76f3bad1921c1d05b0bfc9033e71aadf17d..78fb26b00e8fe0dc86d7b887978aa2bb971a4edb 100644 (file)
@@ -90,6 +90,7 @@ 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 = \
index 6aa7a2c0a94c22140d0278bd0f77e432efe160f4..40da7c8fbe036d90b74f12b224651d9e9dacac94 100644 (file)
@@ -1517,7 +1517,7 @@ def verify_ospf_database(tgen, topo, dut, input_dict, expected=True):
 
 
 @retry(retry_timeout=20)
-def verify_ospf_summary(tgen, topo, dut, input_dict, expected=True):
+def verify_ospf_summary(tgen, topo, dut, input_dict, ospf=None, expected=True):
     """
     This API is to verify ospf routes by running
     show ip ospf interface command.
@@ -1528,7 +1528,6 @@ def verify_ospf_summary(tgen, topo, dut, input_dict, expected=True):
     * `topo` : topology descriptions
     * `dut`: device under test
     * `input_dict` : Input dict data, required when configuring from testcase
-    * `expected` : expected results from API, by-default True
 
     Usage
     -----
@@ -1548,18 +1547,30 @@ def verify_ospf_summary(tgen, topo, dut, input_dict, expected=True):
     True or False (Error Message)
     """
 
-    logger.debug("Entering lib API: verify_ospf_summary()")
+    logger.debug("Entering lib API: {}".format(sys._getframe().f_code.co_name))
     result = False
     router = dut
 
     logger.info("Verifying OSPF summary on router %s:", router)
 
-    if "ospf" not in topo["routers"][dut]:
-        errormsg = "[DUT: {}] OSPF is not configured on the router.".format(router)
-        return errormsg
-
     rnode = tgen.routers()[dut]
-    show_ospf_json = run_frr_cmd(rnode, "show ip ospf summary detail json", isjson=True)
+
+    if ospf:
+        if 'ospf6' not in topo['routers'][dut]:
+            errormsg = "[DUT: {}] OSPF6 is not configured on the router.".format(
+                router)
+            return errormsg
+
+        show_ospf_json = run_frr_cmd(rnode, "show ipv6 ospf summary detail json",
+                                 isjson=True)
+    else:
+        if 'ospf' not in topo['routers'][dut]:
+            errormsg = "[DUT: {}] OSPF is not configured on the router.".format(
+                router)
+            return errormsg
+
+        show_ospf_json = run_frr_cmd(rnode, "show ip ospf summary detail json",
+                                 isjson=True)
 
     # Verifying output dictionary show_ospf_json is empty or not
     if not bool(show_ospf_json):
@@ -1568,35 +1579,31 @@ def verify_ospf_summary(tgen, topo, dut, input_dict, expected=True):
 
     # To find neighbor ip type
     ospf_summary_data = input_dict
+
+    if ospf:
+        show_ospf_json = show_ospf_json['default']
+
     for ospf_summ, summ_data in ospf_summary_data.items():
         if ospf_summ not in show_ospf_json:
             continue
-        summary = ospf_summary_data[ospf_summ]["Summary address"]
+        summary = ospf_summary_data[ospf_summ]['Summary address']
+
         if summary in show_ospf_json:
             for summ in summ_data:
                 if summ_data[summ] == show_ospf_json[summary][summ]:
-                    logger.info(
-                        "[DUT: %s] OSPF summary %s:%s is %s",
-                        router,
-                        summary,
-                        summ,
-                        summ_data[summ],
-                    )
+                    logger.info("[DUT: %s] OSPF summary %s:%s is %s",
+                                router, summary, summ, summ_data[summ])
                     result = True
                 else:
-                    errormsg = (
-                        "[DUT: {}] OSPF summary {}:{} is %s, "
-                        "Expected is {}".format(
-                            router, summary, summ, show_ospf_json[summary][summ]
-                        )
-                    )
+                    errormsg = ("[DUT: {}] OSPF summary {} : {} is {}, "
+                    "Expected is {}".format(router, summary, summ,show_ospf_json[
+                        summary][summ], summ_data[summ] ))
                     return errormsg
 
-    logger.debug("Exiting API: verify_ospf_summary()")
+    logger.debug("Exiting lib API: {}".format(sys._getframe().f_code.co_name))
     return result
 
 
-
 @retry(retry_timeout=30)
 def verify_ospf6_rib(tgen, dut, input_dict, next_hop=None,
             tag=None, metric=None, fib=None):
diff --git a/tests/topotests/ospfv3_basic_functionality/ospfv3_asbr_summary_topo1.json b/tests/topotests/ospfv3_basic_functionality/ospfv3_asbr_summary_topo1.json
new file mode 100644 (file)
index 0000000..74a0de4
--- /dev/null
@@ -0,0 +1,198 @@
+{
+    "address_types": [
+        "ipv6"
+    ],
+    "ipv6base": "fd00::",
+    "ipv6mask": 64,
+    "link_ip_start": {
+        "ipv6": "fd00::",
+        "v6mask": 64
+    },
+    "lo_prefix": {
+        "ipv6": "2001:db8:f::",
+        "v6mask": 128
+    },
+    "routers": {
+        "r0": {
+            "links": {
+                "lo": {
+                    "ipv6": "auto",
+                    "type": "loopback"
+                },
+                "r1": {
+                    "ipv6": "auto",
+                    "ospf6": {
+                        "area": "0.0.0.0",
+                        "hello_interval": 1,
+                        "dead_interval": 4
+                    }
+                },
+                "r2": {
+                    "ipv6": "auto",
+                    "ospf6": {
+                        "area": "0.0.0.0",
+                        "hello_interval": 1,
+                        "dead_interval": 4
+                    }
+                },
+                "r3": {
+                    "ipv6": "auto",
+                    "ospf6": {
+                        "area": "0.0.0.0",
+                        "hello_interval": 1,
+                        "dead_interval": 4,
+                        "network": "point-to-point"
+                    }
+                },
+                "r3-link0": {
+                    "ipv6": "auto",
+                    "description": "DummyIntftoR3"
+                }
+            },
+            "ospf6": {
+                "router_id": "100.1.1.0",
+                "neighbors": {
+                    "r1": {},
+                    "r2": {},
+                    "r3": {}
+                }
+            }
+        },
+        "r1": {
+            "links": {
+                "lo": {
+                    "ipv6": "auto",
+                    "type": "loopback"
+                },
+                "r0": {
+                    "ipv6": "auto",
+                    "ospf6": {
+                        "area": "0.0.0.0",
+                        "hello_interval": 1,
+                        "dead_interval": 4
+                    }
+                },
+                "r2": {
+                    "ipv6": "auto",
+                    "ospf6": {
+                        "area": "0.0.0.0",
+                        "hello_interval": 1,
+                        "dead_interval": 4
+                    }
+                },
+                "r3": {
+                    "ipv6": "auto",
+                    "ospf6": {
+                        "area": "0.0.0.0",
+                        "hello_interval": 1,
+                        "dead_interval": 4
+                    }
+                },
+                "r3-link0": {
+                    "ipv6": "auto",
+                    "description": "DummyIntftoR3"
+                }
+            },
+            "ospf6": {
+                "router_id": "100.1.1.1",
+                "neighbors": {
+                    "r0": {},
+                    "r2": {},
+                    "r3": {}
+                }
+            }
+        },
+        "r2": {
+            "links": {
+                "lo": {
+                    "ipv6": "auto",
+                    "type": "loopback"
+                },
+                "r0": {
+                    "ipv6": "auto",
+                    "ospf6": {
+                        "area": "0.0.0.0",
+                        "hello_interval": 1,
+                        "dead_interval": 4
+                    }
+                },
+                "r1": {
+                    "ipv6": "auto",
+                    "ospf6": {
+                        "area": "0.0.0.0",
+                        "hello_interval": 1,
+                        "dead_interval": 4
+                    }
+                },
+                "r3": {
+                    "ipv6": "auto",
+                    "ospf6": {
+                        "area": "0.0.0.0",
+                        "hello_interval": 1,
+                        "dead_interval": 4
+                    }
+                }
+            },
+            "ospf6": {
+                "router_id": "100.1.1.2",
+                "neighbors": {
+                    "r1": {},
+                    "r0": {},
+                    "r3": {}
+                }
+            }
+        },
+        "r3": {
+            "links": {
+                "lo": {
+                    "ipv6": "auto",
+                    "type": "loopback"
+                },
+                "r0": {
+                    "ipv6": "auto",
+                    "ospf6": {
+                        "area": "0.0.0.0",
+                        "hello_interval": 1,
+                        "dead_interval": 4,
+                        "network": "point-to-point"
+                    }
+                },
+                "r0-link0": {
+                    "ipv6": "auto",
+                    "description": "DummyIntftoR0"
+                },
+                "r1": {
+                    "ipv6": "auto",
+                    "ospf6": {
+                        "area": "0.0.0.0",
+                        "hello_interval": 1,
+                        "dead_interval": 4
+                    }
+                },
+                "r2": {
+                    "ipv6": "auto",
+                    "ospf6": {
+                        "area": "0.0.0.0",
+                        "hello_interval": 1,
+                        "dead_interval": 4
+                    }
+                },
+                "r1-link0": {
+                    "ipv6": "auto",
+                    "description": "DummyIntftoR1",
+                    "ospf6": {
+                        "area": "0.0.0.0"
+                    }
+                }
+            },
+            "ospf6": {
+                "router_id": "100.1.1.3",
+                "neighbors": {
+                    "r0": {},
+                    "r1": {},
+                    "r2": {}
+                }
+            }
+        }
+    }
+}
\ No newline at end of file
diff --git a/tests/topotests/ospfv3_basic_functionality/test_ospfv3_asbr_summary_topo1.py b/tests/topotests/ospfv3_basic_functionality/test_ospfv3_asbr_summary_topo1.py
new file mode 100644 (file)
index 0000000..6a4b60f
--- /dev/null
@@ -0,0 +1,1928 @@
+#!/usr/bin/python
+
+#
+# Copyright (c) 2021 by VMware, Inc. ("VMware")
+# Used Copyright (c) 2018 by Network Device Education Foundation, Inc.
+# ("NetDEF") in this file.
+#
+# Permission to use, copy, modify, and/or distribute this software
+# for any purpose with or without fee is hereby granted, provided
+# that the above copyright notice and this permission notice appear
+# in all copies.
+#
+# THE SOFTWARE IS PROVIDED "AS IS" AND VMWARE DISCLAIMS ALL WARRANTIES
+# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL VMWARE BE LIABLE FOR
+# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY
+# DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+# WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+# ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+# OF THIS SOFTWARE.
+#
+
+
+"""OSPF Summarisation Functionality Automation."""
+import os
+import sys
+import time
+import pytest
+import json
+from copy import deepcopy
+from ipaddress import IPv4Address
+from lib.topotest import frr_unicode
+
+# Save the Current Working Directory to find configuration files.
+CWD = os.path.dirname(os.path.realpath(__file__))
+sys.path.append(os.path.join(CWD, "../"))
+sys.path.append(os.path.join(CWD, "../lib/"))
+
+# pylint: disable=C0413
+# Import topogen and topotest helpers
+from mininet.topo import Topo
+from lib.topogen import Topogen, get_topogen
+import ipaddress
+from time import sleep
+
+# Import topoJson from lib, to create topology and initial configuration
+from lib.common_config import (
+    start_topology,
+    write_test_header,
+    kill_router_daemons,
+    write_test_footer,
+    reset_config_on_routers,
+    stop_router,
+    start_router,
+    verify_rib,
+    create_static_routes,
+    step,
+    start_router_daemons,
+    create_route_maps,
+    shutdown_bringup_interface,
+    create_prefix_lists,
+    create_route_maps,
+    create_interfaces_cfg,
+    topo_daemons,
+)
+from lib.topolog import logger
+from lib.topojson import build_topo_from_json, build_config_from_json
+from lib.ospf import (
+    verify_ospf6_neighbor,
+    clear_ospf,
+    verify_ospf6_rib,
+    create_router_ospf,
+    verify_ospf_summary,
+)
+
+
+# Global variables
+topo = None
+# Reading the data from JSON File for topology creation
+jsonFile = "{}/ospfv3_asbr_summary_topo1.json".format(CWD)
+try:
+    with open(jsonFile, "r") as topoJson:
+        topo = json.load(topoJson)
+except IOError:
+    assert False, "Could not read file {}".format(jsonFile)
+
+NETWORK = {
+    "ipv4": [
+        "11.0.20.1/32",
+        "11.0.20.2/32",
+        "11.0.20.3/32",
+        "11.0.20.4/32",
+        "11.0.20.5/32",
+    ],
+    "ipv6": [
+        "2011:0:20::1/128",
+        "2011:0:20::2/128",
+        "2011:0:20::3/128",
+        "2011:0:20::4/128",
+        "2011:0:20::5/128",
+    ],
+}
+NETWORK_11 = {
+    "ipv4": ["11.0.20.6/32", "11.0.20.7/32"],
+    "ipv6": ["2011:0:20::6/128", "2011:0:20::7/128"],
+}
+
+NETWORK2 = {
+    "ipv4": [
+        "12.0.20.1/32",
+        "12.0.20.2/32",
+        "12.0.20.3/32",
+        "12.0.20.4/32",
+        "12.0.20.5/32",
+    ],
+    "ipv6": [
+        "2012:0:20::1/128",
+        "2012:0:20::2/128",
+        "2012:0:20::3/128",
+        "2012:0:20::4/128",
+        "2012:0:20::5/128",
+    ],
+}
+SUMMARY = {
+    "ipv4": ["11.0.0.0/8", "12.0.0.0/8", "11.0.0.0/24"],
+    "ipv6": ["2011::/32", "2012::/32", "2011::/64", "2011::/24"],
+}
+"""
+TOPOOLOGY =
+      Please view in a fixed-width font such as Courier.
+      +---+  A0       +---+
+      +R1 +------------+R2 |
+      +-+-+-           +--++
+        |  --        --  |
+        |    -- A0 --    |
+      A0|      ----      |
+        |      ----      | A0
+        |    --    --    |
+        |  --        --  |
+      +-+-+-            +-+-+
+      +R0 +-------------+R3 |
+      +---+     A0     +---+
+
+TESTCASES =
+1. OSPF summarisation functionality.
+2. OSPF summarisation with advertise and no advertise option
+3. OSPF summarisation with route map modification of metric type.
+4. OSPF CLI Show  verify ospf ASBR summary config and show commands behaviours.
+5. OSPF summarisation Chaos.
+"""
+
+
+class CreateTopo(Topo):
+    """
+    Test topology builder.
+
+    * `Topo`: Topology object
+    """
+
+    def build(self, *_args, **_opts):
+        """Build function."""
+        tgen = get_topogen(self)
+
+        # Building topology from json file
+        build_topo_from_json(tgen, topo)
+
+
+def setup_module(mod):
+    """
+    Sets up the pytest environment
+
+    * `mod`: module name
+    """
+    global topo
+    testsuite_run_time = time.asctime(time.localtime(time.time()))
+    logger.info("Testsuite start time: {}".format(testsuite_run_time))
+    logger.info("=" * 40)
+
+    logger.info("Running setup_module to create topology")
+
+    # This function initiates the topology build with Topogen...
+    tgen = Topogen(CreateTopo, mod.__name__)
+    # ... and here it calls Mininet initialization functions.
+
+    # get list of daemons needs to be started for this suite.
+    daemons = topo_daemons(tgen, topo)
+
+    # Starting topology, create tmp files which are loaded to routers
+    #  to start deamons and then start routers
+    start_topology(tgen, daemons)
+
+    # Creating configuration from JSON
+    build_config_from_json(tgen, topo)
+
+    # Don't run this test if we have any failure.
+    if tgen.routers_have_failure():
+        pytest.skip(tgen.errors)
+    # Api call verify whether OSPF is converged
+    ospf_covergence = verify_ospf6_neighbor(tgen, topo)
+    assert ospf_covergence is True, "setup_module :Failed \n Error:" " {}".format(
+        ospf_covergence
+    )
+
+    logger.info("Running setup_module() done")
+
+
+def teardown_module(mod):
+    """
+    Teardown the pytest environment.
+
+    * `mod`: module name
+    """
+
+    logger.info("Running teardown_module to delete topology")
+
+    tgen = get_topogen()
+
+    # Stop toplogy and Remove tmp files
+    tgen.stop_topology()
+
+    logger.info(
+        "Testsuite end time: {}".format(time.asctime(time.localtime(time.time())))
+    )
+    logger.info("=" * 40)
+
+
+def red_static(dut, config=True):
+    """
+    Local 'def' for Redstribute static routes inside ospf.
+
+    Parameters
+    ----------
+    * `dut` : DUT on which configs have to be made.
+    * `config` : True or False, True by default for configure, set False for
+                 unconfiguration.
+    """
+    global topo
+    tgen = get_topogen()
+    if config:
+        ospf_red = {dut: {"ospf6": {"redistribute": [{"redist_type": "static"}]}}}
+    else:
+        ospf_red = {
+            dut: {
+                "ospf6": {"redistribute": [{"redist_type": "static", "delete": True}]}
+            }
+        }
+    result = create_router_ospf(tgen, topo, ospf_red)
+    assert result is True, "Testcase : Failed \n Error: {}".format(result)
+
+
+def red_connected(dut, config=True):
+    """
+    Local 'def' for Redstribute connected routes inside ospf
+
+    Parameters
+    ----------
+    * `dut` : DUT on which configs have to be made.
+    * `config` : True or False, True by default for configure, set False for
+                 unconfiguration.
+    """
+    global topo
+    tgen = get_topogen()
+    if config:
+        ospf_red = {dut: {"ospf6": {"redistribute": [{"redist_type": "connected"}]}}}
+    else:
+        ospf_red = {
+            dut: {
+                "ospf6": {
+                    "redistribute": [{"redist_type": "connected", "delete": True}]
+                }
+            }
+        }
+    result = create_router_ospf(tgen, topo, ospf_red)
+    assert result is True, "Testcase: Failed \n Error: {}".format(result)
+
+
+# ##################################
+# Test cases start here.
+# ##################################
+
+def test_ospfv3_type5_summary_tc42_p0(request):
+    """OSPF summarisation functionality."""
+    tc_name = request.node.name
+    write_test_header(tc_name)
+    tgen = get_topogen()
+
+    # Don't run this test if we have any failure.
+    if tgen.routers_have_failure():
+        pytest.skip(tgen.errors)
+
+    global topo
+    step("Bring up the base config as per the topology")
+    reset_config_on_routers(tgen)
+
+    protocol = 'ospf'
+
+    step(
+        "Configure 5 static routes from the same network on R0"
+        "5 static routes from different networks and redistribute in R0")
+    input_dict_static_rtes = {
+        "r0": {
+            "static_routes": [
+                {
+                    "network": NETWORK["ipv6"],
+                    "next_hop": "blackhole"
+                },
+                {
+                    "network": NETWORK2["ipv6"],
+                    "next_hop": "blackhole"
+                }
+            ]
+        }
+    }
+    result = create_static_routes(tgen, input_dict_static_rtes)
+    assert result is True, "Testcase {} : Failed \n Error: {}".format(
+        tc_name, result)
+
+    dut = 'r0'
+    red_static(dut)
+
+    step("Verify that routes are learnt on R1.")
+    dut = 'r1'
+
+    result = verify_ospf6_rib(tgen, dut, input_dict_static_rtes)
+    assert result is True, "Testcase {} : Failed \n Error: {}".format(
+        tc_name, result)
+    result = verify_rib(tgen, "ipv6", dut,
+                        input_dict_static_rtes, protocol=protocol)
+    assert result is True, "Testcase {} : Failed" \
+        "Error: Routes is missing in RIB".format(tc_name)
+
+    step(
+        "Configure External Route summary in R0 to summarise 5"
+        " routes to one route. with aggregate timer as 6 sec")
+
+    ospf_summ_r1 = {
+        "r0": {
+            "ospf6": {
+                "summary-address": [{
+                    "prefix": SUMMARY["ipv6"][0].split('/')[0],
+                    "mask": "32"
+                }],
+                "aggr_timer": 6
+            }
+        }
+    }
+    result = create_router_ospf(tgen, topo, ospf_summ_r1)
+    assert result is True, "Testcase {} : Failed \n Error: {}".format(
+        tc_name, result)
+
+    step(
+        "Verify that external routes are summarised to configured summary "
+        "address on R0 after 5 secs of delay timer expiry and only one "
+        "route is sent to R1.")
+    input_dict_summary = {
+        "r0": {
+            "static_routes": [{"network": SUMMARY["ipv6"][0]}]
+        }
+    }
+    dut = 'r1'
+
+    result = verify_ospf6_rib(tgen, dut, input_dict_summary)
+    assert result is True, "Testcase {} : Failed \n Error: {}".format(
+        tc_name, result)
+
+    result = verify_rib(tgen, "ipv6", dut,
+                        input_dict_summary, protocol=protocol)
+    assert result is True, "Testcase {} : Failed" \
+        "Error: Routes is missing in RIB".format(tc_name)
+
+    step("Verify that show ip ospf summary should show the summaries.")
+    input_dict = {
+        SUMMARY["ipv6"][0]: {
+            "Summary address": SUMMARY["ipv6"][0],
+            "Metric-type": "E2",
+            "Metric": 20,
+            "Tag": 0,
+            "External route count": 5
+        }
+    }
+    dut = 'r0'
+    result = verify_ospf_summary(tgen, topo, dut, input_dict, ospf='ospf6')
+    assert result is True, "Testcase {} : Failed" \
+        "Error: Summary missing in OSPF DB".format(tc_name)
+
+    step(
+        "Verify that originally advertised routes are withdraw from there"
+        " peer.")
+    input_dict = {
+        "r0": {
+            "static_routes": [
+                {
+                    "network": NETWORK["ipv6"],
+                    "next_hop": "blackhole"
+                }
+            ]
+        }
+    }
+    dut = 'r1'
+    result = verify_ospf6_rib(tgen, dut, input_dict, expected=False)
+    assert result is not True, "Testcase {} : Failed \n Error: "\
+    "Routes still present in OSPF RIB {}".format(tc_name, result)
+
+    result = verify_rib(tgen, "ipv6", dut, input_dict, protocol=protocol,
+                            expected=False)
+    assert result is not True, "Testcase {} : Failed" \
+        "Error: Routes still present in RIB".format(tc_name)
+
+    step("Delete the configured summary")
+    ospf_summ_r1 = {
+        "r0": {
+            "ospf6": {
+                "summary-address": [{
+                    "prefix": SUMMARY["ipv6"][0].split('/')[0],
+                    "mask": "32",
+                    "del_aggr_timer": True,
+                    "delete": True
+                }]
+            }
+        }
+    }
+    result = create_router_ospf(tgen, topo, ospf_summ_r1)
+    assert result is True, "Testcase {} : Failed \n Error: {}".format(
+        tc_name, result)
+
+    step("Verify that summary lsa is withdrawn from R1 and deleted from R0.")
+    dut = 'r1'
+    result = verify_ospf6_rib(tgen, dut, input_dict, expected=False)
+    assert result is not True, "Testcase {} : Failed \n Error: "\
+    "Routes still present in OSPF RIB {}".format(tc_name, result)
+
+    result = verify_rib(tgen, "ipv6", dut,
+                        input_dict_summary, protocol=protocol, expected=False)
+    assert result is not True, "Testcase {} : Failed" \
+        "Error: Summary Route still present in RIB".format(tc_name)
+
+    step("show ip ospf summary should not have any summary address.")
+    input_dict = {
+        SUMMARY["ipv6"][0]: {
+            "Summary address": SUMMARY["ipv6"][0],
+            "Metric-type": "E2",
+            "Metric": 20,
+            "Tag": 0,
+            "External route count": 5
+        }
+    }
+    dut = 'r0'
+    result = verify_ospf_summary(tgen, topo, dut, input_dict, ospf='ospf6', expected=False)
+    assert result is not True, "Testcase {} : Failed" \
+        "Error: Summary still present in DB".format(tc_name)
+
+    dut = 'r1'
+    step("All 5 routes are advertised after deletion of configured summary.")
+
+    result = verify_ospf6_rib(tgen, dut, input_dict_static_rtes)
+    assert result is True, "Testcase {} : Failed \n Error: {}".format(
+        tc_name, result)
+
+    result = verify_rib(tgen, "ipv6", dut,
+                        input_dict_static_rtes, protocol=protocol)
+    assert result is True, "Testcase {} : Failed" \
+        "Error: Routes is missing in RIB".format(tc_name)
+
+    step("configure the summary again and delete static routes .")
+    ospf_summ_r1 = {
+        "r0": {
+            "ospf6": {
+                "summary-address": [{
+                    "prefix": SUMMARY["ipv6"][0].split('/')[0],
+                    "mask": "32"
+                }]
+            }
+        }
+    }
+    result = create_router_ospf(tgen, topo, ospf_summ_r1)
+    assert result is True, "Testcase {} : Failed \n Error: {}".format(
+        tc_name, result)
+
+    input_dict = {
+        SUMMARY["ipv6"][0]: {
+            "Summary address": SUMMARY["ipv6"][0],
+            "Metric-type": "E2",
+            "Metric": 20,
+            "Tag": 0,
+            "External route count": 5
+        }
+    }
+    dut = 'r0'
+    result = verify_ospf_summary(tgen, topo, dut, input_dict, ospf='ospf6')
+    assert result is True, "Testcase {} : Failed" \
+        "Error: Summary missing in OSPF DB".format(tc_name)
+
+    input_dict = {
+        "r0": {
+            "static_routes": [
+                {
+                    "network": NETWORK["ipv6"],
+                    "next_hop": "blackhole",
+                    "delete": True
+                }
+            ]
+        }
+    }
+    result = create_static_routes(tgen, input_dict)
+    assert result is True, "Testcase {} : Failed \n Error: {}".format(
+        tc_name, result)
+
+    input_dict_summary = {
+        "r0": {
+            "static_routes": [{"network": SUMMARY["ipv6"][0]}]
+        }
+    }
+    step("Verify that summary route is withdrawn from R1.")
+
+    dut = 'r1'
+    result = verify_ospf6_rib(tgen, dut, input_dict_summary, expected=False)
+    assert result is not True, "Testcase {} : Failed \n Error: "\
+    "Routes still present in OSPF RIB {}".format(tc_name, result)
+
+    result = verify_rib(tgen, "ipv6", dut,
+                        input_dict_summary, protocol=protocol, expected=False)
+    assert result is not True, "Testcase {} : Failed" \
+        "Error: Routes still present in RIB".format(tc_name)
+
+    step("Add back static routes.")
+    input_dict_static_rtes = {
+        "r0": {
+            "static_routes": [
+                {
+                    "network": NETWORK["ipv6"],
+                    "next_hop": "blackhole"
+                }
+            ]
+        }
+    }
+    result = create_static_routes(tgen, input_dict_static_rtes)
+    assert result is True, "Testcase {} : Failed \n Error: {}".format(
+        tc_name, result)
+
+    step(
+        "Verify that external routes are summarised to configured summary"
+        " address on R0 and only one route is sent to R1.")
+    dut = 'r1'
+
+    result = verify_ospf6_rib(tgen, dut, input_dict_static_rtes, expected=False)
+    assert result is not True, "Testcase {} : Failed \n Error: "\
+    "Routes still present in OSPF RIB {}".format(tc_name, result)
+
+    result = verify_rib(
+                            tgen, "ipv6", dut, input_dict_static_rtes,
+                            protocol=protocol, expected=False)
+    assert result is not True, "Testcase {} : Failed" \
+        "Error: Routes still present in RIB".format(tc_name)
+
+    input_dict_summary = {
+        "r0": {
+            "static_routes": [{"network": SUMMARY["ipv6"][0]}]
+        }
+    }
+    dut = 'r1'
+
+    result = verify_ospf6_rib(tgen, dut, input_dict_summary)
+    assert result is True, "Testcase {} : Failed \n Error: {}".format(
+        tc_name, result)
+
+    result = verify_rib(tgen, "ipv6", dut,
+                        input_dict_summary, protocol=protocol)
+    assert result is True, "Testcase {} : Failed" \
+        "Error: Routes is missing in RIB".format(tc_name)
+
+    step("Verify that show ip ospf summary should show configure summaries.")
+
+    input_dict = {
+        SUMMARY["ipv6"][0]: {
+            "Summary address": SUMMARY["ipv6"][0],
+            "Metric-type": "E2",
+            "Metric": 20,
+            "Tag": 0,
+            "External route count": 5
+        }
+    }
+    dut = 'r0'
+    result = verify_ospf_summary(tgen, topo, dut, input_dict, ospf='ospf6')
+    assert result is True, "Testcase {} : Failed" \
+        "Error: Summary missing in OSPF DB".format(tc_name)
+
+    step("Configure new static route which is matching configured summary.")
+    input_dict_static_rtes = {
+        "r0": {
+            "static_routes": [
+                {
+                    "network": NETWORK_11["ipv6"],
+                    "next_hop": "blackhole"
+                }
+            ]
+        }
+    }
+    result = create_static_routes(tgen, input_dict_static_rtes)
+    assert result is True, "Testcase {} : Failed \n Error: {}".format(
+        tc_name, result)
+
+    # step("verify that summary lsa is not refreshed.")
+    # show ip ospf database command is not working, waiting for DEV fix.
+
+    step("Delete one of the static route.")
+    input_dict_static_rtes = {
+        "r0": {
+            "static_routes": [
+                {
+                    "network": NETWORK_11["ipv6"],
+                    "next_hop": "blackhole",
+                    "delete": True
+                }
+            ]
+        }
+    }
+    result = create_static_routes(tgen, input_dict_static_rtes)
+    assert result is True, "Testcase {} : Failed \n Error: {}".format(
+        tc_name, result)
+
+    # step("verify that summary lsa is not refreshed.")
+    # show ip ospf database command is not working, waiting for DEV fix.
+
+    # step("Verify that deleted static route is removed from ospf LSDB.")
+    # show ip ospf database command is not working, waiting for DEV fix.
+
+    step(
+        "Configure redistribute connected and configure ospf external"
+        " summary address to summarise the connected routes.")
+
+    dut = 'r0'
+    red_connected(dut)
+    clear_ospf(tgen, dut, ospf='ospf6')
+
+    ip = topo['routers']['r0']['links']['r3']['ipv6']
+
+    ip_net = str(ipaddress.ip_interface(u'{}'.format(ip)).network)
+    ospf_summ_r1 = {
+        "r0": {
+            "ospf6": {
+                "summary-address": [{
+                    "prefix": ip_net.split('/')[0],
+                    "mask": "8"
+                }]
+            }
+        }
+    }
+    result = create_router_ospf(tgen, topo, ospf_summ_r1)
+    assert result is True, "Testcase {} : Failed \n Error: {}".format(
+        tc_name, result)
+
+    step(
+        "Verify that external routes are summarised to configured "
+        "summary address on R0 and only one route is sent to R1.")
+
+    input_dict_summary = {
+        "r0": {
+            "static_routes": [{"network": "fd00::/64"}]
+        }
+    }
+    dut = 'r1'
+    result = verify_ospf6_rib(tgen, dut, input_dict_summary)
+    assert result is True, "Testcase {} : Failed \n Error: {}".format(
+        tc_name, result)
+
+    result = verify_rib(tgen, "ipv6", dut,
+                        input_dict_summary, protocol=protocol)
+    assert result is True, "Testcase {} : Failed" \
+        "Error: Routes is missing in RIB".format(tc_name)
+
+    step("Shut one of the interface")
+    intf = topo['routers']['r0']['links']['r3-link0']['interface']
+    shutdown_bringup_interface(tgen, dut, intf, False)
+
+    # step("verify that summary lsa is not refreshed.")
+    # show ip ospf database command is not working, waiting for DEV fix.
+
+    # step("Verify that deleted connected route is removed from ospf LSDB.")
+    # show ip ospf database command is not working, waiting for DEV fix.
+
+    step("Un do shut the interface")
+    shutdown_bringup_interface(tgen, dut, intf, True)
+
+    # step("verify that summary lsa is not refreshed.")
+    # show ip ospf database command is not working, waiting for DEV fix.
+
+    # step("Verify that deleted connected route is removed from ospf LSDB.")
+    # show ip ospf database command is not working, waiting for DEV fix.
+
+    step("Delete OSPF process.")
+    ospf_del = {
+        "r0": {
+            "ospf6": {
+                "delete": True
+            }
+        }
+    }
+    result = create_router_ospf(tgen, topo, ospf_del)
+    assert result is True, "Testcase : Failed \n Error: {}".format(result)
+
+    step("Reconfigure ospf process with summary")
+    reset_config_on_routers(tgen)
+
+    input_dict_static_rtes = {
+        "r0": {
+            "static_routes": [
+                {
+                    "network": NETWORK["ipv6"],
+                    "next_hop": "blackhole"
+                },
+                {
+                    "network": NETWORK2["ipv6"],
+                    "next_hop": "blackhole"
+                }
+            ]
+        }
+    }
+    result = create_static_routes(tgen, input_dict_static_rtes)
+    assert result is True, "Testcase {} : Failed \n Error: {}".format(
+        tc_name, result)
+
+    dut = 'r0'
+    red_static(dut)
+    red_connected(dut)
+    ospf_summ_r1 = {
+        "r0": {
+            "ospf6": {
+                "summary-address": [{
+                    "prefix": SUMMARY["ipv6"][0].split('/')[0],
+                    "mask": "32"
+                }]
+            }
+        }
+    }
+    result = create_router_ospf(tgen, topo, ospf_summ_r1)
+    assert result is True, "Testcase {} : Failed \n Error: {}".format(
+        tc_name, result)
+    step(
+        "Verify that external routes are summarised to configured summary "
+        "address on R0 and only one route is sent to R1.")
+
+    input_dict = {
+        SUMMARY["ipv6"][0]: {
+            "Summary address": SUMMARY["ipv6"][0],
+            "Metric-type": "E2",
+            "Metric": 20,
+            "Tag": 0,
+            "External route count": 5
+        }
+    }
+    dut = 'r0'
+    result = verify_ospf_summary(tgen, topo, dut, input_dict, ospf='ospf6')
+    assert result is True, "Testcase {} : Failed" \
+        "Error: Summary missing in OSPF DB".format(tc_name)
+
+
+    input_dict_summary = {
+        "r0": {
+            "static_routes": [{"network": SUMMARY["ipv6"][0]}]
+        }
+    }
+
+    dut = 'r1'
+    result = verify_ospf6_rib(tgen, dut, input_dict_summary)
+    assert result is True, "Testcase {} : Failed \n Error: {}".format(
+        tc_name, result)
+
+    result = verify_rib(tgen, "ipv6", dut,
+                        input_dict_summary, protocol=protocol)
+    assert result is True, "Testcase {} : Failed" \
+        "Error: Routes is missing in RIB".format(tc_name)
+
+    ospf_summ_r1 = {
+        "r0": {
+            "ospf6": {
+                "summary-address": [{
+                    "prefix": SUMMARY["ipv6"][0].split('/')[0],
+                    "mask": "32"
+                }]
+            }
+        }
+    }
+    result = create_router_ospf(tgen, topo, ospf_summ_r1)
+    assert result is True, "Testcase {} : Failed \n Error: {}".format(
+        tc_name, result)
+
+    # step("verify that summary lsa is not refreshed.")
+    # show ip ospf database command is not working, waiting for DEV fix.
+
+    step("Delete the redistribute command in ospf.")
+    dut = 'r0'
+    red_connected(dut, config=False)
+    red_static(dut, config=False)
+
+    step("Verify that summary route is withdrawn from the peer.")
+
+    dut = 'r1'
+    result = verify_ospf6_rib(tgen, dut, input_dict_summary, expected=False)
+    assert result is not True, "Testcase {} : Failed \n Error: "\
+    "Routes still present in OSPF RIB {}".format(tc_name, result)
+
+    result = verify_rib(tgen, "ipv6", dut,
+                        input_dict_summary, protocol=protocol, expected=False)
+    assert result is not True, "Testcase {} : Failed" \
+        "Error: Routes still present in RIB".format(tc_name)
+
+    ospf_summ_r1 = {
+        "r0": {
+            "ospf6": {
+                "summary-address": [{
+                    "prefix": SUMMARY["ipv6"][0].split('/')[0],
+                    "mask": "32",
+                    "metric": "1234"
+                }]
+            }
+        }
+    }
+    result = create_router_ospf(tgen, topo, ospf_summ_r1)
+    assert result is True, "Testcase {} : Failed \n Error: {}".format(
+        tc_name, result)
+
+    write_test_footer(tc_name)
+
+
+def test_ospfv3_type5_summary_tc46_p0(request):
+    """OSPF summarisation with advertise and no advertise option"""
+    tc_name = request.node.name
+    write_test_header(tc_name)
+    tgen = get_topogen()
+
+    # Don't run this test if we have any failure.
+    if tgen.routers_have_failure():
+        pytest.skip(tgen.errors)
+
+    global topo
+    step("Bring up the base config as per the topology")
+    step("Configure OSPF on all the routers of the topology.")
+    reset_config_on_routers(tgen)
+
+    protocol = 'ospf'
+
+    step(
+        "Configure 5 static routes from the same network on R0"
+        "5 static routes from different networks and redistribute in R0")
+    input_dict_static_rtes = {
+        "r0": {
+            "static_routes": [
+                {
+                    "network": NETWORK["ipv6"],
+                    "next_hop": "blackhole"
+                },
+                {
+                    "network": NETWORK2["ipv6"],
+                    "next_hop": "blackhole"
+                }
+            ]
+        }
+    }
+    result = create_static_routes(tgen, input_dict_static_rtes)
+    assert result is True, "Testcase {} : Failed \n Error: {}".format(
+        tc_name, result)
+
+    dut = 'r0'
+    red_static(dut)
+
+    step("Verify that routes are learnt on R1.")
+    dut = 'r1'
+
+    result = verify_ospf6_rib(tgen, dut, input_dict_static_rtes)
+    assert result is True, "Testcase {} : Failed \n Error: {}".format(
+        tc_name, result)
+    result = verify_rib(tgen, "ipv6", dut,
+                        input_dict_static_rtes, protocol=protocol)
+    assert result is True, "Testcase {} : Failed" \
+        "Error: Routes is missing in RIB".format(tc_name)
+
+    step(
+        "Configure External Route summary in R0 to summarise 5"
+        " routes to one route with no advertise option.")
+    ospf_summ_r1 = {
+        "r0": {
+            "ospf6": {
+                "summary-address": [{
+                    "prefix": SUMMARY["ipv6"][0].split('/')[0],
+                    "mask": "32",
+                    "advertise": False
+                }]
+            }
+        }
+    }
+    result = create_router_ospf(tgen, topo, ospf_summ_r1)
+    assert result is True, "Testcase {} : Failed \n Error: {}".format(
+        tc_name, result)
+
+    step(
+        "Verify that external routes are summarised to configured summary"
+        " address on R0 and  summary route is not advertised to neighbor as"
+        " no advertise is configured..")
+
+    input_dict_summary = {
+        "r0": {
+            "static_routes": [{"network": SUMMARY["ipv6"][0]}]
+        }
+    }
+    dut = 'r1'
+
+    result = verify_ospf6_rib(tgen, dut, input_dict_summary, expected=False)
+    assert result is not True, "Testcase {} : Failed \n Error: "\
+    "Routes still present in OSPF RIB {}".format(tc_name, result)
+
+    result = verify_rib(tgen, "ipv6", dut, input_dict_summary,
+                        protocol=protocol, expected=False)
+    assert result is not True, "Testcase {} : Failed" \
+        "Error: Routes still present in RIB".format(tc_name)
+
+    step(
+        "Verify that show ip ospf summary should show the "
+        "configured summaries.")
+    input_dict = {
+        SUMMARY["ipv6"][0]: {
+            "Summary address": SUMMARY["ipv6"][0],
+            "External route count": 5
+        }
+    }
+    dut = 'r0'
+    result = verify_ospf_summary(tgen, topo, dut, input_dict, ospf='ospf6')
+    assert result is True, "Testcase {} : Failed" \
+        "Error: Summary missing in OSPF DB".format(tc_name)
+
+    step("Delete the configured summary")
+    ospf_summ_r1 = {
+        "r0": {
+            "ospf6": {
+                "summary-address": [{
+                    "prefix": SUMMARY["ipv6"][0].split('/')[0],
+                    "mask": "32",
+                    "delete": True
+                }]
+            }
+        }
+    }
+    result = create_router_ospf(tgen, topo, ospf_summ_r1)
+    assert result is True, "Testcase {} : Failed \n Error: {}".format(
+        tc_name, result)
+
+    step("Summary has 5 sec delay timer, sleep 5 secs...")
+    sleep(5)
+
+    step("Verify that summary lsa is withdrawn from R1 and deleted from R0.")
+    dut = 'r1'
+    result = verify_ospf6_rib(tgen, dut, input_dict, expected=False)
+    assert result is not True, "Testcase {} : Failed \n Error: "\
+    "Routes still present in OSPF RIB {}".format(tc_name, result)
+
+    result = verify_rib(tgen, "ipv6", dut,
+                        input_dict_summary, protocol=protocol, expected=False)
+    assert result is not True, "Testcase {} : Failed" \
+        "Error: Summary Route still present in RIB".format(tc_name)
+
+    step("show ip ospf summary should not have any summary address.")
+    input_dict = {
+        SUMMARY["ipv6"][0]: {
+            "Summary address": SUMMARY["ipv6"][0],
+            "Metric-type": "E2",
+            "Metric": 20,
+            "Tag": 1234,
+            "External route count": 5
+        }
+    }
+    dut = 'r0'
+    result = verify_ospf_summary(tgen, topo, dut, input_dict, ospf='ospf6', expected=False)
+    assert result is not True, "Testcase {} : Failed" \
+        "Error: Summary still present in DB".format(tc_name)
+
+    step("Reconfigure summary with no advertise.")
+    ospf_summ_r1 = {
+        "r0": {
+            "ospf6": {
+                "summary-address": [{
+                    "prefix": SUMMARY["ipv6"][0].split('/')[0],
+                    "mask": "32",
+                    "advertise": False
+                }]
+            }
+        }
+    }
+    result = create_router_ospf(tgen, topo, ospf_summ_r1)
+    assert result is True, "Testcase {} : Failed \n Error: {}".format(
+        tc_name, result)
+
+    step(
+        "Verify that external routes are summarised to configured summary"
+        " address on R0 and  summary route is not advertised to neighbor as"
+        " no advertise is configured..")
+
+    input_dict_summary = {
+        "r0": {
+            "static_routes": [{"network": SUMMARY["ipv6"][0]}]
+        }
+    }
+    dut = 'r1'
+
+    result = verify_ospf6_rib(tgen, dut, input_dict_summary, expected=False)
+    assert result is not True, "Testcase {} : Failed \n Error: "\
+    "Routes still present in OSPF RIB {}".format(tc_name, result)
+
+    result = verify_rib(tgen, "ipv6", dut, input_dict_summary,
+                        protocol=protocol, expected=False)
+    assert result is not True, "Testcase {} : Failed" \
+        "Error: Routes still present in RIB".format(tc_name)
+
+    step(
+        "Verify that show ip ospf summary should show the "
+        "configured summaries.")
+    input_dict = {
+        SUMMARY["ipv6"][0]: {
+            "Summary address": SUMMARY["ipv6"][0],
+            "External route count": 5
+        }
+    }
+    dut = 'r0'
+    result = verify_ospf_summary(tgen, topo, dut, input_dict, ospf='ospf6')
+    assert result is True, "Testcase {} : Failed" \
+        "Error: Summary missing in OSPF DB".format(tc_name)
+
+    step(
+        "Change summary address from no advertise to advertise "
+        "(summary-address 10.0.0.0 255.255.0.0)")
+
+    ospf_summ_r1 = {
+        "r0": {
+            "ospf6": {
+                "summary-address": [{
+                    "prefix": SUMMARY["ipv6"][0].split('/')[0],
+                    "mask": "32",
+                    "advertise": False
+                }]
+            }
+        }
+    }
+    result = create_router_ospf(tgen, topo, ospf_summ_r1)
+    assert result is True, "Testcase {} : Failed \n Error: {}".format(
+        tc_name, result)
+
+    ospf_summ_r1 = {
+        "r0": {
+            "ospf6": {
+                "summary-address": [{
+                    "prefix": SUMMARY["ipv6"][0].split('/')[0],
+                    "mask": "32"
+                }]
+            }
+        }
+    }
+    result = create_router_ospf(tgen, topo, ospf_summ_r1)
+    assert result is True, "Testcase {} : Failed \n Error: {}".format(
+        tc_name, result)
+
+    step(
+        "Verify that external routes are summarised to configured summary "
+        "address on R0 after 5 secs of delay timer expiry and only one "
+        "route is sent to R1.")
+    input_dict_summary = {
+        "r0": {
+            "static_routes": [{"network": SUMMARY["ipv6"][0]}]
+        }
+    }
+    dut = 'r1'
+
+    result = verify_ospf6_rib(tgen, dut, input_dict_summary)
+    assert result is True, "Testcase {} : Failed \n Error: {}".format(
+        tc_name, result)
+
+    result = verify_rib(tgen, "ipv6", dut,
+                        input_dict_summary, protocol=protocol)
+    assert result is True, "Testcase {} : Failed" \
+        "Error: Routes is missing in RIB".format(tc_name)
+
+    step("Verify that show ip ospf summary should show the summaries.")
+    input_dict = {
+        SUMMARY["ipv6"][0]: {
+            "Summary address": SUMMARY["ipv6"][0],
+            "Metric-type": "E2",
+            "Metric": 20,
+            "Tag": 0,
+            "External route count": 5
+        }
+    }
+    dut = 'r0'
+    result = verify_ospf_summary(tgen, topo, dut, input_dict, ospf='ospf6')
+    assert result is True, "Testcase {} : Failed" \
+        "Error: Summary missing in OSPF DB".format(tc_name)
+
+    step(
+        "Verify that originally advertised routes are withdraw from there"
+        " peer.")
+    input_dict = {
+        "r0": {
+            "static_routes": [
+                {
+                    "network": NETWORK["ipv6"],
+                    "next_hop": "blackhole"
+                }
+            ]
+        }
+    }
+    dut = 'r1'
+    result = verify_ospf6_rib(tgen, dut, input_dict, expected=False)
+    assert result is not True, "Testcase {} : Failed \n Error: "\
+    "Routes still present in OSPF RIB {}".format(tc_name, result)
+
+    result = verify_rib(tgen, "ipv6", dut, input_dict, protocol=protocol,
+                            expected=False)
+    assert result is not True, "Testcase {} : Failed" \
+        "Error: Routes is present in RIB".format(tc_name)
+
+    write_test_footer(tc_name)
+
+
+def test_ospfv3_type5_summary_tc48_p0(request):
+    """OSPF summarisation with route map modification of metric type."""
+    tc_name = request.node.name
+    write_test_header(tc_name)
+    tgen = get_topogen()
+
+    # Don't run this test if we have any failure.
+    if tgen.routers_have_failure():
+        pytest.skip(tgen.errors)
+
+    global topo
+    step("Bring up the base config as per the topology")
+    reset_config_on_routers(tgen)
+
+    protocol = 'ospf'
+
+    step(
+        "Configure 5 static routes from the same network on R0"
+        "5 static routes from different networks and redistribute in R0")
+    input_dict_static_rtes = {
+        "r0": {
+            "static_routes": [
+                {
+                    "network": NETWORK["ipv6"],
+                    "next_hop": "blackhole"
+                },
+                {
+                    "network": NETWORK2["ipv6"],
+                    "next_hop": "blackhole"
+                }
+            ]
+        }
+    }
+    result = create_static_routes(tgen, input_dict_static_rtes)
+    assert result is True, "Testcase {} : Failed \n Error: {}".format(
+        tc_name, result)
+
+    dut = 'r0'
+    red_static(dut)
+
+    step("Verify that routes are learnt on R1.")
+    dut = 'r1'
+
+    result = verify_ospf6_rib(tgen, dut, input_dict_static_rtes)
+    assert result is True, "Testcase {} : Failed \n Error: {}".format(
+        tc_name, result)
+    result = verify_rib(tgen, "ipv6", dut,
+                        input_dict_static_rtes, protocol=protocol)
+    assert result is True, "Testcase {} : Failed" \
+        "Error: Routes is missing in RIB".format(tc_name)
+
+    step(
+        "Configure External Route summary in R0 to summarise 5"
+        " routes to one route.")
+
+    ospf_summ_r1 = {
+        "r0": {
+            "ospf6": {
+                "summary-address": [{
+                    "prefix": SUMMARY["ipv6"][0].split('/')[0],
+                    "mask": "32"
+                }]
+            }
+        }
+    }
+    result = create_router_ospf(tgen, topo, ospf_summ_r1)
+    assert result is True, "Testcase {} : Failed \n Error: {}".format(
+        tc_name, result)
+
+    step(
+        "Verify that external routes are summarised to configured summary "
+        "address on R0 after 5 secs of delay timer expiry and only one "
+        "route is sent to R1.")
+    input_dict_summary = {
+        "r0": {
+            "static_routes": [{"network": SUMMARY["ipv6"][0]}]
+        }
+    }
+    dut = 'r1'
+
+    result = verify_ospf6_rib(tgen, dut, input_dict_summary)
+    assert result is True, "Testcase {} : Failed \n Error: {}".format(
+        tc_name, result)
+
+    result = verify_rib(tgen, "ipv6", dut,
+                        input_dict_summary, protocol=protocol)
+    assert result is True, "Testcase {} : Failed" \
+        "Error: Routes is missing in RIB".format(tc_name)
+
+    step("Verify that show ip ospf summary should show the summaries.")
+    input_dict = {
+        SUMMARY["ipv6"][0]: {
+            "Summary address": SUMMARY["ipv6"][0],
+            "Metric-type": "E2",
+            "Metric": 20,
+            "Tag": 0,
+            "External route count": 5
+        }
+    }
+    dut = 'r0'
+    result = verify_ospf_summary(tgen, topo, dut, input_dict, ospf='ospf6')
+    assert result is True, "Testcase {} : Failed" \
+        "Error: Summary missing in OSPF DB".format(tc_name)
+
+    step(
+        "Verify that originally advertised routes are withdraw from there"
+        " peer.")
+    input_dict = {
+        "r0": {
+            "static_routes": [
+                {
+                    "network": NETWORK["ipv6"],
+                    "next_hop": "blackhole"
+                }
+            ]
+        }
+    }
+    dut = 'r1'
+    result = verify_ospf6_rib(tgen, dut, input_dict, expected=False)
+    assert result is not True, "Testcase {} : Failed \n Error: "\
+    "Routes still present in OSPF RIB {}".format(tc_name, result)
+
+    result = verify_rib(tgen, "ipv6", dut, input_dict, protocol=protocol,
+                        expected=False)
+    assert result is not True, "Testcase {} : Failed" \
+        "Error: Routes still present in RIB".format(tc_name)
+
+    step(
+        "Configure route map and & rule to permit configured summary address,"
+        " redistribute static & connected routes with the route map.")
+    step("Configure prefixlist to permit the static routes, add to route map.")
+    # Create ip prefix list
+    pfx_list = {
+        "r0": {
+            "prefix_lists": {
+                "ipv6": {
+                    "pf_list_1_ipv6": [
+                    {
+                        "seqid": 10,
+                        "network": "any",
+                        "action": "permit"
+                    }
+                    ]
+                }
+            }
+        }
+    }
+    result = create_prefix_lists(tgen, pfx_list)
+    assert result is True, "Testcase {} : Failed \n Error: {}".format(
+        tc_name, result)
+
+
+    routemaps = {
+            "r0": {
+                "route_maps": {
+                    "rmap_ipv6": [{
+                        "action": "permit",
+                        "seq_id": '1',
+                        "match": {
+                            "ipv6": {
+                                "prefix_lists":
+                                    "pf_list_1_ipv6"
+                            }
+                        }
+                    }]
+                }
+            }
+    }
+    result = create_route_maps(tgen, routemaps)
+    assert result is True, "Testcase {} : Failed \n Error: {}".format(
+        tc_name, result)
+
+    ospf_red_r1 = {
+        "r0": {
+            "ospf6": {
+                "redistribute": [{
+                    "redist_type": "static",
+                    "route_map": "rmap_ipv6"
+                }]
+            }
+        }
+    }
+    result = create_router_ospf(tgen, topo, ospf_red_r1)
+    assert result is True, "Testcase {} : Failed \n Error: {}".format(
+        tc_name, result)
+
+    step(
+        "Verify that external routes are summarised to configured"
+        "summary address on R0 and only one route is sent to R1. Verify that "
+        "show ip ospf summary should show the configure summaries.")
+
+    input_dict_summary = {
+        "r0": {
+            "static_routes": [{"network": SUMMARY["ipv6"][0]}]
+        }
+    }
+    dut = 'r1'
+
+    result = verify_ospf6_rib(tgen, dut, input_dict_summary)
+    assert result is True, "Testcase {} : Failed \n Error: {}".format(
+        tc_name, result)
+
+    result = verify_rib(tgen, "ipv6", dut,
+                        input_dict_summary, protocol=protocol)
+    assert result is True, "Testcase {} : Failed" \
+        "Error: Routes is missing in RIB".format(tc_name)
+
+    input_dict = {
+        SUMMARY["ipv6"][0]: {
+            "Summary address": SUMMARY["ipv6"][0],
+            "Metric-type": "E2",
+            "Metric": 20,
+            "Tag": 0,
+            "External route count": 5
+        }
+    }
+    dut = 'r0'
+    result = verify_ospf_summary(tgen, topo, dut, input_dict, ospf='ospf6')
+    assert result is True, "Testcase {} : Failed" \
+        "Error: Summary missing in OSPF DB".format(tc_name)
+
+    step("Configure metric type as 1 in route map.")
+
+
+    routemaps = {
+            "r0": {
+                "route_maps": {
+                    "rmap_ipv6": [{
+                        "seq_id": '1',
+                        "action": "permit",
+                        "set":{
+                            "metric-type": "type-1"
+                        }
+                    }]
+                }
+            }
+    }
+    result = create_route_maps(tgen, routemaps)
+    assert result is True, "Testcase {} : Failed \n Error: {}".format(
+        tc_name, result)
+
+    step(
+        "Verify that external routes(static / connected) are summarised"
+        " to configured summary address with metric type 2.")
+    input_dict = {
+        SUMMARY["ipv6"][0]: {
+            "Summary address": SUMMARY["ipv6"][0],
+            "Metric-type": "E2",
+            "Metric": 20,
+            "Tag": 0,
+            "External route count": 5
+        }
+    }
+    dut = 'r0'
+    result = verify_ospf_summary(tgen, topo, dut, input_dict, ospf='ospf6')
+    assert result is True, "Testcase {} : Failed" \
+        "Error: Summary missing in OSPF DB".format(tc_name)
+
+    step("Un configure metric type from route map.")
+
+    routemaps = {
+            "r0": {
+                "route_maps": {
+                    "rmap_ipv6": [{
+                        "action": "permit",
+                        "seq_id": '1',
+                        "set":{
+                            "metric-type": "type-1",
+                            "delete": True
+                        }
+                    }]
+                }
+            }
+    }
+    result = create_route_maps(tgen, routemaps)
+    assert result is True, "Testcase {} : Failed \n Error: {}".format(
+        tc_name, result)
+
+    step(
+        "Verify that external routes(static / connected) are summarised"
+        " to configured summary address with metric type 2.")
+    input_dict = {
+        SUMMARY["ipv6"][0]: {
+            "Summary address": SUMMARY["ipv6"][0],
+            "Metric-type": "E2",
+            "Metric": 20,
+            "Tag": 0,
+            "External route count": 5
+        }
+    }
+    dut = 'r0'
+    result = verify_ospf_summary(tgen, topo, dut, input_dict, ospf='ospf6')
+    assert result is True, "Testcase {} : Failed" \
+        "Error: Summary missing in OSPF DB".format(tc_name)
+
+    step("Change rule from permit to deny in prefix list.")
+    pfx_list = {
+        "r0": {
+            "prefix_lists": {
+                "ipv6": {
+                    "pf_list_1_ipv6": [
+                    {
+                        "seqid": 10,
+                        "network": "any",
+                        "action": "deny"
+                    }
+                    ]
+                }
+            }
+        }
+    }
+    result = create_prefix_lists(tgen, pfx_list)
+    assert result is True, "Testcase {} : Failed \n Error: {}".format(
+        tc_name, result)
+
+    step(
+        "Verify that previously originated summary lsa "
+        "is withdrawn from the neighbor.")
+    input_dict_summary = {
+        "r0": {
+            "static_routes": [{"network": SUMMARY["ipv6"][0]}]
+        }
+    }
+    dut = 'r1'
+
+    step("summary route has delay of 5 secs, wait for 5 secs")
+
+    sleep(5)
+
+    result = verify_ospf6_rib(tgen, dut, input_dict_summary, expected=False)
+    assert result is not True, "Testcase {} : Failed \n Error: "\
+    "Routes still present in OSPF RIB {}".format(tc_name, result)
+
+    result = verify_rib(tgen, "ipv6", dut,
+                        input_dict_summary, protocol=protocol, expected=False)
+    assert result is not True, "Testcase {} : Failed" \
+        "Error: Routes still present in RIB".format(tc_name)
+
+    write_test_footer(tc_name)
+
+
+def test_ospfv3_type5_summary_tc51_p2(request):
+    """OSPF CLI Show.
+
+    verify ospf ASBR summary config and show commands behaviours.
+    """
+    tc_name = request.node.name
+    write_test_header(tc_name)
+    tgen = get_topogen()
+
+    # Don't run this test if we have any failure.
+    if tgen.routers_have_failure():
+        pytest.skip(tgen.errors)
+
+    global topo
+    step("Bring up the base config as per the topology")
+    reset_config_on_routers(tgen)
+
+    step("Configure all the supported OSPF ASBR summary commands on DUT.")
+    ospf_summ_r1 = {
+        "r0": {
+            "ospf6": {
+                "summary-address": [{
+                    "prefix": SUMMARY["ipv6"][0].split('/')[0],
+                    "mask": "32",
+                    "tag": 4294967295
+                },
+                {
+                    "prefix": SUMMARY["ipv6"][0].split('/')[0],
+                    "mask": "16",
+                    "advertise": True
+                },
+                {
+                    "prefix": SUMMARY["ipv6"][0].split('/')[0],
+                    "mask": "24",
+                    "advertise": False
+                },
+                {
+                    "prefix": SUMMARY["ipv6"][0].split('/')[0],
+                    "mask": "24",
+                    "advertise": False
+                },
+                ]
+            }
+        }
+    }
+    result = create_router_ospf(tgen, topo, ospf_summ_r1)
+    assert result is True, "Testcase {} : Failed \n Error: {}".format(
+        tc_name, result)
+
+
+    step("Configure and re configure all the commands 10 times in a loop.")
+
+    for itrate in range(0,10):
+        ospf_summ_r1 = {
+            "r0": {
+                "ospf6": {
+                    "summary-address": [{
+                        "prefix": SUMMARY["ipv6"][0].split('/')[0],
+                        "mask": "8",
+                        "tag": 4294967295
+                    },
+                    {
+                        "prefix": SUMMARY["ipv6"][0].split('/')[0],
+                        "mask": "16",
+                        "advertise": True
+                    },
+                    {
+                        "prefix": SUMMARY["ipv6"][0].split('/')[0],
+                        "mask": "24",
+                        "advertise": False
+                    },
+                    {
+                        "prefix": SUMMARY["ipv6"][0].split('/')[0],
+                        "mask": "24",
+                        "advertise": False
+                    },
+                    ]
+                }
+             }
+        }
+        result = create_router_ospf(tgen, topo, ospf_summ_r1)
+        assert result is True, "Testcase {} : Failed \n Error: {}".format(
+            tc_name, result)
+
+        ospf_summ_r1 = {
+            "r0": {
+                "ospf6": {
+                    "summary-address": [{
+                        "prefix": SUMMARY["ipv6"][0].split('/')[0],
+                        "mask": "8",
+                        "tag": 4294967295,
+                        "delete": True
+                    },
+                    {
+                        "prefix": SUMMARY["ipv6"][0].split('/')[0],
+                        "mask": "16",
+                        "advertise": True,
+                        "delete": True
+                    },
+                    {
+                        "prefix": SUMMARY["ipv6"][0].split('/')[0],
+                        "mask": "24",
+                        "advertise": False,
+                        "delete": True
+                    },
+                    {
+                        "prefix": SUMMARY["ipv6"][0].split('/')[0],
+                        "mask": "24",
+                        "advertise": False,
+                        "delete": True
+                    },
+                    ]
+                }
+        }
+    }
+    result = create_router_ospf(tgen, topo, ospf_summ_r1)
+    assert result is True, "Testcase {} : Failed \n Error: {}".format(
+        tc_name, result)
+
+    step("Verify the show commands")
+
+    input_dict = {
+        SUMMARY["ipv6"][3]: {
+            "Summary address": SUMMARY["ipv6"][3],
+            "Metric-type": "E2",
+            "Metric": 20,
+            "Tag": 0,
+            "External route count": 0
+        }
+    }
+    dut = 'r0'
+    result = verify_ospf_summary(tgen, topo, dut, input_dict, ospf='ospf6')
+    assert result is True, "Testcase {} : Failed" \
+        "Error: Summary missing in OSPF DB".format(tc_name)
+
+    write_test_footer(tc_name)
+
+
+def test_ospfv3_type5_summary_tc49_p2(request):
+    """OSPF summarisation Chaos."""
+    tc_name = request.node.name
+    write_test_header(tc_name)
+    tgen = get_topogen()
+
+    # Don't run this test if we have any failure.
+    if tgen.routers_have_failure():
+        pytest.skip(tgen.errors)
+
+    global topo
+    step("Bring up the base config as per the topology")
+    reset_config_on_routers(tgen)
+
+    protocol = 'ospf'
+
+    step(
+        "Configure 5 static routes from the same network on R0"
+        "5 static routes from different networks and redistribute in R0")
+    input_dict_static_rtes = {
+        "r0": {
+            "static_routes": [
+                {
+                    "network": NETWORK["ipv6"],
+                    "next_hop": "blackhole"
+                },
+                {
+                    "network": NETWORK2["ipv6"],
+                    "next_hop": "blackhole"
+                }
+            ]
+        }
+    }
+    result = create_static_routes(tgen, input_dict_static_rtes)
+    assert result is True, "Testcase {} : Failed \n Error: {}".format(
+        tc_name, result)
+
+    dut = 'r0'
+    red_static(dut)
+
+    step("Verify that routes are learnt on R1.")
+    dut = 'r1'
+
+    result = verify_ospf6_rib(tgen, dut, input_dict_static_rtes)
+    assert result is True, "Testcase {} : Failed \n Error: {}".format(
+        tc_name, result)
+    result = verify_rib(tgen, "ipv6", dut,
+                        input_dict_static_rtes, protocol=protocol)
+    assert result is True, "Testcase {} : Failed" \
+        "Error: Routes is missing in RIB".format(tc_name)
+
+    step(
+        "Configure External Route summary in R0 to summarise 5"
+        " routes to one route.")
+
+    ospf_summ_r1 = {
+        "r0": {
+            "ospf6": {
+                "summary-address": [{
+                    "prefix": SUMMARY["ipv6"][0].split('/')[0],
+                    "mask": "32"
+                }]
+            }
+        }
+    }
+    result = create_router_ospf(tgen, topo, ospf_summ_r1)
+    assert result is True, "Testcase {} : Failed \n Error: {}".format(
+        tc_name, result)
+
+    step(
+        "Verify that external routes are summarised to configured summary "
+        "address on R0 after 5 secs of delay timer expiry and only one "
+        "route is sent to R1.")
+    input_dict_summary = {
+        "r0": {
+            "static_routes": [{"network": SUMMARY["ipv6"][0]}]
+        }
+    }
+    dut = 'r1'
+
+    result = verify_ospf6_rib(tgen, dut, input_dict_summary)
+    assert result is True, "Testcase {} : Failed \n Error: {}".format(
+        tc_name, result)
+
+    result = verify_rib(tgen, "ipv6", dut,
+                        input_dict_summary, protocol=protocol)
+    assert result is True, "Testcase {} : Failed" \
+        "Error: Routes is missing in RIB".format(tc_name)
+
+    step("Verify that show ip ospf summary should show the summaries.")
+    input_dict = {
+        SUMMARY["ipv6"][0]: {
+            "Summary address": SUMMARY["ipv6"][0],
+            "Metric-type": "E2",
+            "Metric": 20,
+            "Tag": 0,
+            "External route count": 5
+        }
+    }
+    dut = 'r0'
+    result = verify_ospf_summary(tgen, topo, dut, input_dict, ospf='ospf6')
+    assert result is True, "Testcase {} : Failed" \
+        "Error: Summary missing in OSPF DB".format(tc_name)
+
+    step(
+        "Verify that originally advertised routes are withdraw from there"
+        " peer.")
+    input_dict = {
+        "r0": {
+            "static_routes": [
+                {
+                    "network": NETWORK["ipv6"],
+                    "next_hop": "blackhole"
+                }
+            ]
+        }
+    }
+    dut = 'r1'
+    result = verify_ospf6_rib(tgen, dut, input_dict, expected=False)
+    assert result is not True, "Testcase {} : Failed \n Error: "\
+    "Routes still present in OSPF RIB {}".format(tc_name, result)
+
+    result = verify_rib(tgen, "ipv6", dut, input_dict, protocol=protocol,
+                        expected=False)
+    assert result is not True, "Testcase {} : Failed" \
+        "Error: Routes still present in RIB".format(tc_name)
+
+    step('Reload the FRR router')
+    # stop/start -> restart FRR router and verify
+    stop_router(tgen, 'r0')
+    start_router(tgen, 'r0')
+
+    step(
+        "Verify that external routes are summarised to configured summary "
+        "address on R0 after 5 secs of delay timer expiry and only one "
+        "route is sent to R1.")
+    input_dict_summary = {
+        "r0": {
+            "static_routes": [{"network": SUMMARY["ipv6"][0]}]
+        }
+    }
+    dut = 'r1'
+
+    result = verify_ospf6_rib(tgen, dut, input_dict_summary)
+    assert result is True, "Testcase {} : Failed \n Error: {}".format(
+        tc_name, result)
+
+    result = verify_rib(tgen, "ipv6", dut,
+                        input_dict_summary, protocol=protocol)
+    assert result is True, "Testcase {} : Failed" \
+        "Error: Routes is missing in RIB".format(tc_name)
+
+    step("Verify that show ip ospf summary should show the summaries.")
+    input_dict = {
+        SUMMARY["ipv6"][0]: {
+            "Summary address": SUMMARY["ipv6"][0],
+            "Metric-type": "E2",
+            "Metric": 20,
+            "Tag": 0,
+            "External route count": 5
+        }
+    }
+    dut = 'r0'
+    result = verify_ospf_summary(tgen, topo, dut, input_dict, ospf='ospf6')
+    assert result is True, "Testcase {} : Failed" \
+        "Error: Summary missing in OSPF DB".format(tc_name)
+
+    step(
+        "Verify that originally advertised routes are withdraw from there"
+        " peer.")
+    input_dict = {
+        "r0": {
+            "static_routes": [
+                {
+                    "network": NETWORK["ipv6"],
+                    "next_hop": "blackhole"
+                }
+            ]
+        }
+    }
+    dut = 'r1'
+    result = verify_ospf6_rib(tgen, dut, input_dict, expected=False)
+    assert result is not True, "Testcase {} : Failed \n Error: "\
+    "Routes still present in OSPF RIB {}".format(tc_name, result)
+
+    result = verify_rib(tgen, "ipv6", dut, input_dict, protocol=protocol,
+                        expected=False)
+    assert result is not True, "Testcase {} : Failed" \
+        "Error: Routes still present in RIB".format(tc_name)
+
+    step("Kill OSPF6d daemon on R0.")
+    kill_router_daemons(tgen, "r0", ["ospf6d"])
+
+    step("Bring up OSPF6d daemon on R0.")
+    start_router_daemons(tgen, "r0", ["ospf6d"])
+
+    step("Verify OSPF neighbors are up after bringing back ospf6d in R0")
+    # Api call verify whether OSPF is converged
+    ospf_covergence = verify_ospf6_neighbor(tgen, topo)
+    assert ospf_covergence is True, ("setup_module :Failed \n Error:"
+                                          " {}".format(ospf_covergence))
+
+    step(
+        "Verify that external routes are summarised to configured summary "
+        "address on R0 after 5 secs of delay timer expiry and only one "
+        "route is sent to R1.")
+    input_dict_summary = {
+        "r0": {
+            "static_routes": [{"network": SUMMARY["ipv6"][0]}]
+        }
+    }
+    dut = 'r1'
+
+    result = verify_ospf6_rib(tgen, dut, input_dict_summary)
+    assert result is True, "Testcase {} : Failed \n Error: {}".format(
+        tc_name, result)
+
+    result = verify_rib(tgen, "ipv6", dut,
+                        input_dict_summary, protocol=protocol)
+    assert result is True, "Testcase {} : Failed" \
+        "Error: Routes is missing in RIB".format(tc_name)
+
+    step("Verify that show ip ospf summary should show the summaries.")
+    input_dict = {
+        SUMMARY["ipv6"][0]: {
+            "Summary address": SUMMARY["ipv6"][0],
+            "Metric-type": "E2",
+            "Metric": 20,
+            "Tag": 0,
+            "External route count": 5
+        }
+    }
+    dut = 'r0'
+    result = verify_ospf_summary(tgen, topo, dut, input_dict, ospf='ospf6')
+    assert result is True, "Testcase {} : Failed" \
+        "Error: Summary missing in OSPF DB".format(tc_name)
+
+    step(
+        "Verify that originally advertised routes are withdraw from there"
+        " peer.")
+    input_dict = {
+        "r0": {
+            "static_routes": [
+                {
+                    "network": NETWORK["ipv6"],
+                    "next_hop": "blackhole"
+                }
+            ]
+        }
+    }
+    dut = 'r1'
+    result = verify_ospf6_rib(tgen, dut, input_dict, expected=False)
+    assert result is not True, "Testcase {} : Failed \n Error: "\
+    "Routes still present in OSPF RIB {}".format(tc_name, result)
+
+    result = verify_rib(tgen, "ipv6", dut, input_dict, protocol=protocol,
+                        expected=False)
+    assert result is not True, "Testcase {} : Failed" \
+        "Error: Routes still present in RIB".format(tc_name)
+
+    step("restart zebrad")
+    kill_router_daemons(tgen, "r0", ["zebra"])
+
+    step("Bring up zebra daemon on R0.")
+    start_router_daemons(tgen, "r0", ["zebra"])
+
+    step(
+        "Verify that external routes are summarised to configured summary "
+        "address on R0 after 5 secs of delay timer expiry and only one "
+        "route is sent to R1.")
+    input_dict_summary = {
+        "r0": {
+            "static_routes": [{"network": SUMMARY["ipv6"][0]}]
+        }
+    }
+    dut = 'r1'
+
+    result = verify_ospf6_rib(tgen, dut, input_dict_summary)
+    assert result is True, "Testcase {} : Failed \n Error: {}".format(
+        tc_name, result)
+
+    result = verify_rib(tgen, "ipv6", dut,
+                        input_dict_summary, protocol=protocol)
+    assert result is True, "Testcase {} : Failed" \
+        "Error: Routes is missing in RIB".format(tc_name)
+
+    step("Verify that show ip ospf summary should show the summaries.")
+    input_dict = {
+        SUMMARY["ipv6"][0]: {
+            "Summary address": SUMMARY["ipv6"][0],
+            "Metric-type": "E2",
+            "Metric": 20,
+            "Tag": 0,
+            "External route count": 5
+        }
+    }
+    dut = 'r0'
+    result = verify_ospf_summary(tgen, topo, dut, input_dict, ospf='ospf6')
+    assert result is True, "Testcase {} : Failed" \
+        "Error: Summary missing in OSPF DB".format(tc_name)
+
+    step(
+        "Verify that originally advertised routes are withdraw from there"
+        " peer.")
+    input_dict = {
+        "r0": {
+            "static_routes": [
+                {
+                    "network": NETWORK["ipv6"],
+                    "next_hop": "blackhole"
+                }
+            ]
+        }
+    }
+    dut = 'r1'
+    result = verify_ospf6_rib(tgen, dut, input_dict, expected=False)
+    assert result is not True, "Testcase {} : Failed \n Error: "\
+    "Routes still present in OSPF RIB {}".format(tc_name, result)
+
+    result = verify_rib(tgen, "ipv6", dut, input_dict, protocol=protocol,
+                        expected=False)
+    assert result is not True, "Testcase {} : Failed" \
+        "Error: Routes still present in RIB".format(tc_name)
+
+    write_test_footer(tc_name)
+
+
+if __name__ == "__main__":
+    args = ["-s"] + sys.argv[1:]
+    sys.exit(pytest.main(args))