]> git.proxmox.com Git - mirror_frr.git/commitdiff
ospf6d: Support for nssa in ospfv3
authorKaushik <kaushiknath.null@gmail.com>
Thu, 25 Mar 2021 11:29:51 +0000 (04:29 -0700)
committerRafael Zalamena <rzalamena@opensourcerouting.org>
Fri, 4 Jun 2021 10:23:10 +0000 (07:23 -0300)
The following is implemented.
1. Configuring area as NSSA.
2. Generating Type 7 LSA.
3. Conversion of Type 7 to Type 5 ( Default Behavior).
4. NSSA ABR selection.

Reviewed-by: Rafael Zalamena <rzalamena@opensourcerouting.org>
Co-authored-by: Kaushik <kaushiknath.null@gmail.com>
Co-authored-by: Soman K.S <somanks@gmail.com>
Signed-off-by: Kaushik <kaushiknath.null@gmail.com>
23 files changed:
ospf6d/ospf6_abr.c
ospf6d/ospf6_abr.h
ospf6d/ospf6_area.c
ospf6d/ospf6_area.h
ospf6d/ospf6_asbr.c
ospf6d/ospf6_asbr.h
ospf6d/ospf6_flood.c
ospf6d/ospf6_flood.h
ospf6d/ospf6_interface.c
ospf6d/ospf6_interface.h
ospf6d/ospf6_intra.c
ospf6d/ospf6_lsa.c
ospf6d/ospf6_lsa.h
ospf6d/ospf6_lsdb.c
ospf6d/ospf6_nssa.c [new file with mode: 0644]
ospf6d/ospf6_nssa.h [new file with mode: 0644]
ospf6d/ospf6_proto.h
ospf6d/ospf6_spf.c
ospf6d/ospf6_spf.h
ospf6d/ospf6_top.c
ospf6d/ospf6_top.h
ospf6d/ospf6d.c
ospf6d/subdir.am

index 1af8aed1a9c3474e3bef1ee3330e21272843a56c..a43118cb21a2ae258aa753626eebcbd03beace2c 100644 (file)
@@ -49,6 +49,7 @@
 #include "ospf6_asbr.h"
 #include "ospf6_abr.h"
 #include "ospf6d.h"
+#include "ospf6_nssa.h"
 
 unsigned char conf_debug_ospf6_abr;
 
@@ -57,14 +58,29 @@ int ospf6_is_router_abr(struct ospf6 *o)
        struct listnode *node;
        struct ospf6_area *oa;
        int area_count = 0;
+       bool is_backbone = false;
 
-       for (ALL_LIST_ELEMENTS_RO(o->area_list, node, oa))
+       for (ALL_LIST_ELEMENTS_RO(o->area_list, node, oa)) {
+               if (IS_OSPF6_DEBUG_ABR)
+                       zlog_debug("%s, area_id %pI4", __func__, &oa->area_id);
                if (IS_AREA_ENABLED(oa))
                        area_count++;
 
-       if (area_count > 1)
+               if (o->backbone == oa)
+                       is_backbone = true;
+       }
+
+       if ((area_count > 1) && (is_backbone)) {
+               if (IS_OSPF6_DEBUG_ABR)
+                       zlog_debug("%s : set flag OSPF6_FLAG_ABR", __func__);
+               SET_FLAG(o->flag, OSPF6_FLAG_ABR);
                return 1;
-       return 0;
+       } else {
+               if (IS_OSPF6_DEBUG_ABR)
+                       zlog_debug("%s : reset flag OSPF6_FLAG_ABR", __func__);
+               UNSET_FLAG(o->flag, OSPF6_FLAG_ABR);
+               return 0;
+       }
 }
 
 static int ospf6_abr_nexthops_belong_to_area(struct ospf6_route *route,
@@ -156,37 +172,72 @@ int ospf6_abr_originate_summary_to_area(struct ospf6_route *route,
        uint16_t type;
        int is_debug = 0;
 
+       if (IS_OSPF6_DEBUG_ABR)
+               zlog_debug("%s : start area %s, route %pFX", __func__,
+                          area->name, &route->prefix);
+
+       if (route->type == OSPF6_DEST_TYPE_ROUTER)
+               summary_table = area->summary_router;
+       else
+               summary_table = area->summary_prefix;
+
+       summary = ospf6_route_lookup(&route->prefix, summary_table);
+       if (summary) {
+               old = ospf6_lsdb_lookup(summary->path.origin.type,
+                                       summary->path.origin.id,
+                                       area->ospf6->router_id, area->lsdb);
+               /* Reset the OSPF6_LSA_UNAPPROVED flag */
+               if (old)
+                       UNSET_FLAG(old->flag, OSPF6_LSA_UNAPPROVED);
+       }
+
        /* Only destination type network, range or ASBR are considered */
        if (route->type != OSPF6_DEST_TYPE_NETWORK
            && route->type != OSPF6_DEST_TYPE_RANGE
            && ((route->type != OSPF6_DEST_TYPE_ROUTER)
                || !CHECK_FLAG(route->path.router_bits, OSPF6_ROUTER_BIT_E))) {
+               if (IS_OSPF6_DEBUG_ABR)
+                       zlog_debug(
+                               "%s: Route type %d flag 0x%x is none of network, range nor ASBR, ignore",
+                               __func__, route->type, route->path.router_bits);
                return 0;
        }
 
        /* AS External routes are never considered */
        if (route->path.type == OSPF6_PATH_TYPE_EXTERNAL1
            || route->path.type == OSPF6_PATH_TYPE_EXTERNAL2) {
+               if (IS_OSPF6_DEBUG_ABR)
+                       zlog_debug("%s : Path type is external, skip",
+                                  __func__);
                return 0;
        }
 
        /* do not generate if the path's area is the same as target area */
        if (route->path.area_id == area->area_id) {
+               if (IS_OSPF6_DEBUG_ABR)
+                       zlog_debug(
+                               "%s: The route is in the area itself, ignore",
+                               __func__);
                return 0;
        }
 
        /* do not generate if the nexthops belongs to the target area */
        if (ospf6_abr_nexthops_belong_to_area(route, area)) {
+               if (IS_OSPF6_DEBUG_ABR)
+                       zlog_debug(
+                               "%s: The route's nexthop is in the same area, ignore",
+                               __func__);
                return 0;
        }
 
        if (route->type == OSPF6_DEST_TYPE_ROUTER) {
                if (ADV_ROUTER_IN_PREFIX(&route->prefix)
                    == area->ospf6->router_id) {
-                       zlog_debug(
-                               "%s: Skipping ASBR announcement for ABR (%pI4)",
-                               __func__,
-                               &ADV_ROUTER_IN_PREFIX(&route->prefix));
+                       if (IS_OSPF6_DEBUG_ABR)
+                               zlog_debug(
+                                       "%s: Skipping ASBR announcement for ABR (%pI4)",
+                                       __func__,
+                                       &ADV_ROUTER_IN_PREFIX(&route->prefix));
                        return 0;
                }
        }
@@ -195,12 +246,12 @@ int ospf6_abr_originate_summary_to_area(struct ospf6_route *route,
                if (IS_OSPF6_DEBUG_ABR
                    || IS_OSPF6_DEBUG_ORIGINATE(INTER_ROUTER)) {
                        is_debug++;
-                       zlog_debug(
-                               "Originating summary in area %s for ASBR %pI4",
-                               area->name,
-                               &ADV_ROUTER_IN_PREFIX(&route->prefix));
+                       if (IS_OSPF6_DEBUG_ABR)
+                               zlog_debug(
+                                       "Originating summary in area %s for ASBR %pI4",
+                                       area->name,
+                                       &ADV_ROUTER_IN_PREFIX(&route->prefix));
                }
-               summary_table = area->summary_router;
        } else {
                if (IS_OSPF6_DEBUG_ABR
                    || IS_OSPF6_DEBUG_ORIGINATE(INTER_PREFIX))
@@ -235,15 +286,8 @@ int ospf6_abr_originate_summary_to_area(struct ospf6_route *route,
                        zlog_debug(
                                "Originating summary in area %s for %pFX cost %u",
                                area->name, &route->prefix, route->path.cost);
-               summary_table = area->summary_prefix;
        }
 
-       summary = ospf6_route_lookup(&route->prefix, summary_table);
-       if (summary)
-               old = ospf6_lsdb_lookup(summary->path.origin.type,
-                                       summary->path.origin.id,
-                                       area->ospf6->router_id, area->lsdb);
-
        /* if this route has just removed, remove corresponding LSA */
        if (CHECK_FLAG(route->flag, OSPF6_ROUTE_REMOVE)) {
                if (is_debug)
@@ -496,9 +540,15 @@ int ospf6_abr_originate_summary_to_area(struct ospf6_route *route,
        /* create LSA */
        lsa = ospf6_lsa_create(lsa_header);
 
+       /* Reset the unapproved flag */
+       UNSET_FLAG(lsa->flag, OSPF6_LSA_UNAPPROVED);
+
        /* Originate */
        ospf6_lsa_originate_area(lsa, area);
 
+       if (IS_OSPF6_DEBUG_ABR)
+               zlog_debug("%s : finish area %s", __func__, area->name);
+
        return 1;
 }
 
@@ -566,8 +616,7 @@ ospf6_abr_range_summary_needs_update(struct ospf6_route *range, uint32_t cost)
        return (redo_summary);
 }
 
-static void ospf6_abr_range_update(struct ospf6_route *range,
-                                  struct ospf6 *ospf6)
+void ospf6_abr_range_update(struct ospf6_route *range, struct ospf6 *ospf6)
 {
        uint32_t cost = 0;
        struct listnode *node, *nnode;
@@ -579,6 +628,10 @@ static void ospf6_abr_range_update(struct ospf6_route *range,
        /* update range's cost and active flag */
        cost = ospf6_abr_range_compute_cost(range, ospf6);
 
+       if (IS_OSPF6_DEBUG_ABR)
+               zlog_debug("%s: range %pFX, cost %d", __func__, &range->prefix,
+                          cost);
+
        /* Non-zero cost is a proxy for active longer prefixes in this range.
         * If there are active routes covered by this range AND either the
         * configured
@@ -595,6 +648,9 @@ static void ospf6_abr_range_update(struct ospf6_route *range,
         */
 
        if (ospf6_abr_range_summary_needs_update(range, cost)) {
+               if (IS_OSPF6_DEBUG_ABR)
+                       zlog_debug("%s: range %pFX update", __func__,
+                                  &range->prefix);
                for (ALL_LIST_ELEMENTS(ospf6->area_list, node, nnode, oa))
                        summary_orig +=
                                ospf6_abr_originate_summary_to_area(range, oa);
@@ -628,6 +684,8 @@ void ospf6_abr_originate_summary(struct ospf6_route *route, struct ospf6 *ospf6)
        struct ospf6_area *oa;
        struct ospf6_route *range = NULL;
 
+       if (IS_OSPF6_DEBUG_ABR)
+               zlog_debug("%s: route %pFX", __func__, &route->prefix);
 
        if (route->type == OSPF6_DEST_TYPE_NETWORK) {
                oa = ospf6_area_lookup(route->path.area_id, ospf6);
index 6a912ac63055e4781b9fed5456d44bcaa7629705..7c1ff4d38987a6c8629b29189a90cac6cc81f68c 100644 (file)
@@ -56,6 +56,7 @@ struct ospf6_inter_router_lsa {
        }
 
 #define OSPF6_ABR_RANGE_CLEAR_COST(range) (range->path.cost = OSPF_AREA_RANGE_COST_UNSPEC)
+#define IS_OSPF6_ABR(o) ((o)->flag & OSPF6_FLAG_ABR)
 
 extern int ospf6_is_router_abr(struct ospf6 *o);
 
@@ -88,5 +89,8 @@ extern void ospf6_abr_old_path_update(struct ospf6_route *old_route,
                                      struct ospf6_route_table *table);
 extern void ospf6_abr_init(void);
 extern void ospf6_abr_reexport(struct ospf6_area *oa);
+extern void ospf6_abr_range_update(struct ospf6_route *range,
+                                  struct ospf6 *ospf6);
+extern void ospf6_abr_remove_unapproved_summaries(struct ospf6 *ospf6);
 
 #endif /*OSPF6_ABR_H*/
index d65e40279dc57c0cf6818ae82b3071f1266b1e3b..d879f365be0816b889575c430b9f7a0e53c25fa8 100644 (file)
 #include "ospf6_asbr.h"
 #include "ospf6d.h"
 #include "lib/json.h"
+#include "ospf6_nssa.h"
 
 DEFINE_MTYPE_STATIC(OSPF6D, OSPF6_AREA,      "OSPF6 area");
 DEFINE_MTYPE_STATIC(OSPF6D, OSPF6_PLISTNAME, "Prefix list name");
 
+/* Utility functions. */
+int str2area_id(const char *str, struct in_addr *area_id, int *area_id_fmt)
+{
+       char *ep;
+
+       area_id->s_addr = htonl(strtoul(str, &ep, 10));
+       if (*ep && !inet_aton(str, area_id))
+               return -1;
+
+       *area_id_fmt = *ep ? OSPF6_AREA_FMT_DECIMAL : OSPF6_AREA_FMT_DOTTEDQUAD;
+
+       return 0;
+}
+
 int ospf6_area_cmp(void *va, void *vb)
 {
        struct ospf6_area *oa = (struct ospf6_area *)va;
@@ -60,6 +75,7 @@ int ospf6_area_cmp(void *va, void *vb)
 static void ospf6_area_lsdb_hook_add(struct ospf6_lsa *lsa)
 {
        switch (ntohs(lsa->header->type)) {
+
        case OSPF6_LSTYPE_ROUTER:
        case OSPF6_LSTYPE_NETWORK:
                if (IS_OSPF6_DEBUG_EXAMIN_TYPE(lsa->header->type)) {
@@ -82,6 +98,10 @@ static void ospf6_area_lsdb_hook_add(struct ospf6_lsa *lsa)
                                         (struct ospf6_area *)lsa->lsdb->data);
                break;
 
+       case OSPF6_LSTYPE_TYPE_7:
+               ospf6_asbr_lsa_add(lsa);
+               break;
+
        default:
                break;
        }
@@ -611,6 +631,8 @@ void ospf6_area_config_write(struct vty *vty, struct ospf6 *ospf6)
                        else
                                vty_out(vty, " area %s stub\n", oa->name);
                }
+               if (IS_AREA_NSSA(oa))
+                       vty_out(vty, " area %s nssa\n", oa->name);
                if (PREFIX_NAME_IN(oa))
                        vty_out(vty, " area %s filter-list prefix %s in\n",
                                oa->name, PREFIX_NAME_IN(oa));
@@ -1216,6 +1238,48 @@ DEFUN (no_ospf6_area_stub_no_summary,
        return CMD_SUCCESS;
 }
 
+DEFUN(ospf6_area_nssa, ospf6_area_nssa_cmd,
+      "area <A.B.C.D|(0-4294967295)> nssa",
+      "OSPF6 area parameters\n"
+      "OSPF6 area ID in IP address format\n"
+      "OSPF6 area ID as a decimal value\n"
+      "Configure OSPF6 area as nssa\n")
+{
+       int idx_ipv4_number = 1;
+       struct ospf6_area *area;
+
+       VTY_DECLVAR_CONTEXT(ospf6, ospf6);
+       OSPF6_CMD_AREA_GET(argv[idx_ipv4_number]->arg, area, ospf6);
+
+       if (!ospf6_area_nssa_set(ospf6, area)) {
+               vty_out(vty,
+                       "First deconfigure all virtual link through this area\n");
+               return CMD_WARNING_CONFIG_FAILED;
+       }
+
+       return CMD_SUCCESS;
+}
+
+DEFUN(no_ospf6_area_nssa, no_ospf6_area_nssa_cmd,
+      "no area <A.B.C.D|(0-4294967295)> nssa",
+      NO_STR
+      "OSPF6 area parameters\n"
+      "OSPF6 area ID in IP address format\n"
+      "OSPF6 area ID as a decimal value\n"
+      "Configure OSPF6 area as nssa\n")
+{
+       int idx_ipv4_number = 2;
+       struct ospf6_area *area;
+
+       VTY_DECLVAR_CONTEXT(ospf6, ospf6);
+       OSPF6_CMD_AREA_GET(argv[idx_ipv4_number]->arg, area, ospf6);
+
+       ospf6_area_nssa_unset(ospf6, area);
+
+       return CMD_SUCCESS;
+}
+
+
 void ospf6_area_init(void)
 {
        install_element(VIEW_NODE, &show_ipv6_ospf6_spf_tree_cmd);
@@ -1237,6 +1301,10 @@ void ospf6_area_init(void)
 
        install_element(OSPF6_NODE, &area_filter_list_cmd);
        install_element(OSPF6_NODE, &no_area_filter_list_cmd);
+
+       /* "area nssa" commands. */
+       install_element(OSPF6_NODE, &ospf6_area_nssa_cmd);
+       install_element(OSPF6_NODE, &no_ospf6_area_nssa_cmd);
 }
 
 void ospf6_area_interface_delete(struct ospf6_interface *oi)
index 761fe75f73a5b1dc6d78a754c6258c7e1cbd9b96..fa761d732dd9691b1bfcd12114f0fa74f17ad776 100644 (file)
@@ -106,17 +106,27 @@ struct ospf6_area {
 
        uint32_t full_nbrs; /* Fully adjacent neighbors. */
        uint8_t intra_prefix_originate; /* Force intra_prefix lsa originate */
+       uint8_t NSSATranslatorRole;     /* NSSA configured role */
+#define OSPF6_NSSA_ROLE_NEVER     0
+#define OSPF6_NSSA_ROLE_CANDIDATE 1
+#define OSPF6_NSSA_ROLE_ALWAYS    2
+       uint8_t NSSATranslatorState; /* NSSA operational role */
+#define OSPF6_NSSA_TRANSLATE_DISABLED 0
+#define OSPF6_NSSA_TRANSLATE_ENABLED  1
 };
 
+#define OSPF6_AREA_DEFAULT    0x00
 #define OSPF6_AREA_ENABLE     0x01
 #define OSPF6_AREA_ACTIVE     0x02
 #define OSPF6_AREA_TRANSIT    0x04 /* TransitCapability */
 #define OSPF6_AREA_STUB       0x08
+#define OSPF6_AREA_NSSA       0x10
 
 #define IS_AREA_ENABLED(oa) (CHECK_FLAG ((oa)->flag, OSPF6_AREA_ENABLE))
 #define IS_AREA_ACTIVE(oa) (CHECK_FLAG ((oa)->flag, OSPF6_AREA_ACTIVE))
 #define IS_AREA_TRANSIT(oa) (CHECK_FLAG ((oa)->flag, OSPF6_AREA_TRANSIT))
 #define IS_AREA_STUB(oa) (CHECK_FLAG ((oa)->flag, OSPF6_AREA_STUB))
+#define IS_AREA_NSSA(oa) (CHECK_FLAG((oa)->flag, OSPF6_AREA_NSSA))
 
 #define OSPF6_CMD_AREA_GET(str, oa, ospf6)                                     \
        {                                                                      \
@@ -153,5 +163,6 @@ extern void ospf6_area_config_write(struct vty *vty, struct ospf6 *ospf6);
 extern void ospf6_area_init(void);
 struct ospf6_interface;
 extern void ospf6_area_interface_delete(struct ospf6_interface *oi);
+int str2area_id(const char *str, struct in_addr *area_id, int *area_id_fmt);
 
 #endif /* OSPF_AREA_H */
index 35f50898a686fb42053cd3d809ee092f2969fc21..9d2c1eb10eb3305ef6a766fd9cd958b7c25321a3 100644 (file)
@@ -50,6 +50,8 @@
 #include "ospf6_intra.h"
 #include "ospf6_flood.h"
 #include "ospf6d.h"
+#include "ospf6_spf.h"
+#include "ospf6_nssa.h"
 #include "lib/json.h"
 
 DEFINE_MTYPE_STATIC(OSPF6D, OSPF6_EXTERNAL_INFO, "OSPF6 ext. info");
@@ -69,8 +71,8 @@ unsigned char conf_debug_ospf6_asbr = 0;
 #define ZROUTE_NAME(x) zebra_route_string(x)
 
 /* AS External LSA origination */
-static void ospf6_as_external_lsa_originate(struct ospf6_route *route,
-                                           struct ospf6 *ospf6)
+void ospf6_as_external_lsa_originate(struct ospf6_route *route,
+                                    struct ospf6 *ospf6)
 {
        char buffer[OSPF6_MAX_LSASIZE];
        struct ospf6_lsa_header *lsa_header;
@@ -458,13 +460,48 @@ void ospf6_asbr_update_route_ecmp_path(struct ospf6_route *old,
        }
 }
 
+/* Check if the forwarding address is local address */
+static int ospf6_ase_forward_address_check(struct ospf6 *ospf6,
+                                          struct in6_addr *fwd_addr)
+{
+       struct listnode *anode, *node, *cnode;
+       struct ospf6_interface *oi;
+       struct ospf6_area *oa;
+       struct interface *ifp;
+       struct connected *c;
+
+       for (ALL_LIST_ELEMENTS_RO(ospf6->area_list, anode, oa)) {
+               for (ALL_LIST_ELEMENTS_RO(oa->if_list, node, oi)) {
+                       if (!if_is_operative(oi->interface)
+                           || oi->type == OSPF_IFTYPE_VIRTUALLINK)
+                               continue;
+
+                       ifp = oi->interface;
+                       for (ALL_LIST_ELEMENTS_RO(ifp->connected, cnode, c)) {
+                               if (IPV6_ADDR_SAME(&c->address->u.prefix6,
+                                                  fwd_addr))
+                                       return 0;
+                       }
+               }
+       }
+
+       return 1;
+}
+
 void ospf6_asbr_lsa_add(struct ospf6_lsa *lsa)
 {
        struct ospf6_as_external_lsa *external;
        struct prefix asbr_id;
-       struct ospf6_route *asbr_entry, *route, *old;
+       struct ospf6_route *asbr_entry, *route, *old = NULL;
        struct ospf6_path *path;
        struct ospf6 *ospf6;
+       int type;
+       struct ospf6_area *oa = NULL;
+       struct prefix fwd_addr;
+       ptrdiff_t offset;
+
+       type = ntohs(lsa->header->type);
+       oa = lsa->lsdb->data;
 
        external = (struct ospf6_as_external_lsa *)OSPF6_LSA_HEADER_END(
                lsa->header);
@@ -495,11 +532,53 @@ void ospf6_asbr_lsa_add(struct ospf6_lsa *lsa)
 
        ospf6_linkstate_prefix(lsa->header->adv_router, htonl(0), &asbr_id);
        asbr_entry = ospf6_route_lookup(&asbr_id, ospf6->brouter_table);
-       if (asbr_entry == NULL
-           || !CHECK_FLAG(asbr_entry->path.router_bits, OSPF6_ROUTER_BIT_E)) {
+       if (asbr_entry == NULL) {
                if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL))
                        zlog_debug("ASBR entry not found: %pFX", &asbr_id);
                return;
+       } else {
+               /* The router advertising external LSA can be ASBR or ABR */
+               if (!CHECK_FLAG(asbr_entry->path.router_bits,
+                               OSPF6_ROUTER_BIT_E)) {
+                       if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL))
+                               zlog_debug(
+                                       "External bit reset ASBR route entry : %pFX",
+                                       &asbr_id);
+                       return;
+               }
+       }
+
+       /* Check the forwarding address */
+       if (CHECK_FLAG(external->bits_metric, OSPF6_ASBR_BIT_F)) {
+               offset = sizeof(*external)
+                        + OSPF6_PREFIX_SPACE(external->prefix.prefix_length);
+               memset(&fwd_addr, 0, sizeof(struct prefix));
+               fwd_addr.family = AF_INET6;
+               fwd_addr.prefixlen = IPV6_MAX_PREFIXLEN;
+               memcpy(&fwd_addr.u.prefix6, (caddr_t)external + offset,
+                      sizeof(struct in6_addr));
+
+               if (!IN6_IS_ADDR_UNSPECIFIED(&fwd_addr.u.prefix6)) {
+                       if (!ospf6_ase_forward_address_check(
+                                   ospf6, &fwd_addr.u.prefix6)) {
+                               if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL))
+                                       zlog_debug(
+                                               "Fwd address %pFX is local address",
+                                               &fwd_addr);
+                               return;
+                       }
+
+                       /* Find the forwarding entry */
+                       asbr_entry = ospf6_route_lookup_bestmatch(
+                               &fwd_addr, ospf6->route_table);
+                       if (asbr_entry == NULL) {
+                               if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL))
+                                       zlog_debug(
+                                               "Fwd address not found: %pFX",
+                                               &fwd_addr);
+                               return;
+                       }
+               }
        }
 
        route = ospf6_route_create();
@@ -540,22 +619,38 @@ void ospf6_asbr_lsa_add(struct ospf6_lsa *lsa)
 
        if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL))
                zlog_debug(
-                       "%s: AS-External %u route add %pFX cost %u(%u) nh %u",
-                       __func__,
+                       "%s: %s %u route add %pFX cost %u(%u) nh %u", __func__,
+                       (type == OSPF6_LSTYPE_AS_EXTERNAL) ? "AS-External"
+                                                          : "NSSA",
                        (route->path.type == OSPF6_PATH_TYPE_EXTERNAL1) ? 1 : 2,
                        &route->prefix, route->path.cost, route->path.u.cost_e2,
                        listcount(route->nh_list));
 
-       old = ospf6_route_lookup(&route->prefix, ospf6->route_table);
+       if (type == OSPF6_LSTYPE_AS_EXTERNAL)
+               old = ospf6_route_lookup(&route->prefix, ospf6->route_table);
+       else if (type == OSPF6_LSTYPE_TYPE_7)
+               old = ospf6_route_lookup(&route->prefix, oa->route_table);
        if (!old) {
+               if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL))
+                       zlog_debug("%s : Adding new route", __func__);
                /* Add the new route to ospf6 instance route table. */
-               ospf6_route_add(route, ospf6->route_table);
+               if (type == OSPF6_LSTYPE_AS_EXTERNAL)
+                       ospf6_route_add(route, ospf6->route_table);
+               /* Add the route to the area route table */
+               else if (type == OSPF6_LSTYPE_TYPE_7) {
+                       ospf6_route_add(route, oa->route_table);
+               }
        } else {
                /* RFC 2328 16.4 (6)
                 * ECMP: Keep new equal preference path in current
                 * route's path list, update zebra with new effective
                 * list along with addition of ECMP path.
                 */
+               if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL))
+                       zlog_debug("%s : old route %pFX cost %u(%u) nh %u",
+                                  __func__, &route->prefix, route->path.cost,
+                                  route->path.u.cost_e2,
+                                  listcount(route->nh_list));
                ospf6_asbr_update_route_ecmp_path(old, route, ospf6);
        }
 }
@@ -937,7 +1032,7 @@ void ospf6_asbr_distribute_list_update(int type, struct ospf6 *ospf6)
                              &ospf6->t_distribute_update);
 }
 
-static void ospf6_asbr_routemap_update(const char *mapname)
+void ospf6_asbr_routemap_update(const char *mapname)
 {
        int type;
        struct listnode *node, *nnode;
@@ -1015,7 +1110,7 @@ static void ospf6_asbr_routemap_event(const char *name)
 
 int ospf6_asbr_is_asbr(struct ospf6 *o)
 {
-       return o->external_table->count;
+       return (o->external_table->count || IS_OSPF6_ASBR(o));
 }
 
 struct ospf6_redist *ospf6_redist_lookup(struct ospf6 *ospf6, int type,
@@ -1072,9 +1167,50 @@ static void ospf6_redist_del(struct ospf6 *ospf6, struct ospf6_redist *red,
        }
 }
 
+/*Set the status of the ospf instance to ASBR based on the status parameter,
+ * rechedule SPF calculation, originate router LSA*/
+void ospf6_asbr_status_update(struct ospf6 *ospf6, int status)
+{
+       struct listnode *lnode, *lnnode;
+       struct ospf6_area *oa;
+
+       zlog_info("ASBR[%s:Status:%d]: Update", ospf6->name, status);
+
+       if (status) {
+               if (IS_OSPF6_ASBR(ospf6)) {
+                       zlog_info("ASBR[%s:Status:%d]: Already ASBR",
+                                 ospf6->name, status);
+                       return;
+               }
+               SET_FLAG(ospf6->flag, OSPF6_FLAG_ASBR);
+       } else {
+               if (!IS_OSPF6_ASBR(ospf6)) {
+                       zlog_info("ASBR[%s:Status:%d]: Already non ASBR",
+                                 ospf6->name, status);
+                       return;
+               }
+               UNSET_FLAG(ospf6->flag, OSPF6_FLAG_ASBR);
+       }
+
+       /* Transition from/to status ASBR, schedule timer. */
+       ospf6_spf_schedule(ospf6, OSPF6_SPF_FLAGS_ASBR_STATUS_CHANGE);
+
+       /* Reoriginate router LSA for all areas */
+       for (ALL_LIST_ELEMENTS(ospf6->area_list, lnode, lnnode, oa))
+               OSPF6_ROUTER_LSA_SCHEDULE(oa);
+}
+
 static void ospf6_asbr_redistribute_set(int type, vrf_id_t vrf_id)
 {
+       struct ospf6 *ospf6 = NULL;
        ospf6_zebra_redistribute(type, vrf_id);
+
+       ospf6 = ospf6_lookup_by_vrf_id(vrf_id);
+
+       if (!ospf6)
+               return;
+
+       ospf6_asbr_status_update(ospf6, ++ospf6->redist_count);
 }
 
 static void ospf6_asbr_redistribute_unset(struct ospf6 *ospf6,
@@ -1096,6 +1232,8 @@ static void ospf6_asbr_redistribute_unset(struct ospf6 *ospf6,
        }
 
        ospf6_asbr_routemap_unset(red);
+       zlog_debug("%s: redist_count %d", __func__, ospf6->redist_count);
+       ospf6_asbr_status_update(ospf6, --ospf6->redist_count);
 }
 
 /* When an area is unstubified, flood all the external LSAs in the area */
@@ -1139,35 +1277,6 @@ void ospf6_asbr_remove_externals_from_area(struct ospf6_area *oa)
        }
 }
 
-/* Update ASBR status. */
-static void ospf6_asbr_status_update(struct ospf6 *ospf6, uint8_t status)
-{
-       struct listnode *lnode, *lnnode;
-       struct ospf6_area *oa;
-
-       zlog_info("ASBR[%s:Status:%d]: Update", ospf6->name, status);
-
-       if (status) {
-               if (IS_OSPF6_ASBR(ospf6)) {
-                       zlog_info("ASBR[%s:Status:%d]: Already ASBR",
-                                 ospf6->name, status);
-                       return;
-               }
-               SET_FLAG(ospf6->flag, OSPF6_FLAG_ASBR);
-       } else {
-               if (!IS_OSPF6_ASBR(ospf6)) {
-                       zlog_info("ASBR[%s:Status:%d]: Already non ASBR",
-                                 ospf6->name, status);
-                       return;
-               }
-               UNSET_FLAG(ospf6->flag, OSPF6_FLAG_ASBR);
-       }
-
-       ospf6_spf_schedule(ospf6, OSPF6_SPF_FLAGS_ASBR_STATUS_CHANGE);
-       for (ALL_LIST_ELEMENTS(ospf6->area_list, lnode, lnnode, oa))
-               OSPF6_ROUTER_LSA_SCHEDULE(oa);
-}
-
 void ospf6_asbr_redistribute_add(int type, ifindex_t ifindex,
                                 struct prefix *prefix,
                                 unsigned int nexthop_num,
@@ -1175,6 +1284,8 @@ 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;
@@ -1276,6 +1387,11 @@ 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_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;
        }
 
@@ -1334,13 +1450,19 @@ void ospf6_asbr_redistribute_add(int type, ifindex_t ifindex,
        route->path.origin.id = htonl(info->id);
        ospf6_as_external_lsa_originate(route, ospf6);
        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(route, oa);
+       }
 }
 
 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;
@@ -1369,8 +1491,27 @@ void ospf6_asbr_redistribute_remove(int type, ifindex_t ifindex,
 
        lsa = ospf6_lsdb_lookup(htons(OSPF6_LSTYPE_AS_EXTERNAL),
                                htonl(info->id), ospf6->router_id, ospf6->lsdb);
-       if (lsa)
+       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);
+               }
+       }
 
        /* remove binding in external_id_table */
        prefix_id.family = AF_INET;
@@ -2278,11 +2419,20 @@ static struct ospf6_lsa_handler as_external_handler = {
        .lh_get_prefix_str = ospf6_as_external_lsa_get_prefix_str,
        .lh_debug = 0};
 
+static struct ospf6_lsa_handler nssa_external_handler = {
+       .lh_type = OSPF6_LSTYPE_TYPE_7,
+       .lh_name = "NSSA",
+       .lh_short_name = "Type7",
+       .lh_show = ospf6_as_external_lsa_show,
+       .lh_get_prefix_str = ospf6_as_external_lsa_get_prefix_str,
+       .lh_debug = 0};
+
 void ospf6_asbr_init(void)
 {
        ospf6_routemap_init();
 
        ospf6_install_lsa_handler(&as_external_handler);
+       ospf6_install_lsa_handler(&nssa_external_handler);
 
        install_element(VIEW_NODE, &show_ipv6_ospf6_redistribute_cmd);
 
index 4774ac435a1bbc1e65ea316482cae79d07ebd50c..418c157f368912f1fa878a1864c1dfc334c8d5e7 100644 (file)
@@ -71,6 +71,7 @@ struct ospf6_as_external_lsa {
        }
 
 extern void ospf6_asbr_lsa_add(struct ospf6_lsa *lsa);
+
 extern void ospf6_asbr_lsa_remove(struct ospf6_lsa *lsa,
                                  struct ospf6_route *asbr_entry);
 extern void ospf6_asbr_lsentry_add(struct ospf6_route *asbr_entry,
@@ -106,4 +107,9 @@ extern void ospf6_asbr_update_route_ecmp_path(struct ospf6_route *old,
 extern void ospf6_asbr_distribute_list_update(int type, 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 void ospf6_asbr_status_update(struct ospf6 *ospf6, int status);
+
 #endif /* OSPF6_ASBR_H */
index 76e81aab7b853f295c7c7a69d2e43cf0c66bb683..ac16e53d632ff8083220e0779c0b574634ec5a1d 100644 (file)
@@ -40,6 +40,7 @@
 #include "ospf6_neighbor.h"
 
 #include "ospf6_flood.h"
+#include "ospf6_nssa.h"
 
 unsigned char conf_debug_ospf6_flooding;
 
@@ -213,12 +214,19 @@ void ospf6_install_lsa(struct ospf6_lsa *lsa)
 {
        struct timeval now;
        struct ospf6_lsa *old;
+       struct ospf6_area *area = NULL;
 
        /* Remove the old instance from all neighbors' Link state
           retransmission list (RFC2328 13.2 last paragraph) */
        old = ospf6_lsdb_lookup(lsa->header->type, lsa->header->id,
                                lsa->header->adv_router, lsa->lsdb);
        if (old) {
+               if (ntohs(lsa->header->type) == OSPF6_LSTYPE_TYPE_7) {
+                       if (IS_OSPF6_DEBUG_NSSA)
+                               zlog_debug("%s : old LSA %s", __func__,
+                                          lsa->name);
+                       lsa->external_lsa_id = old->external_lsa_id;
+               }
                THREAD_OFF(old->expire);
                THREAD_OFF(old->refresh);
                ospf6_flood_clear(old);
@@ -265,6 +273,22 @@ void ospf6_install_lsa(struct ospf6_lsa *lsa)
        lsa->installed = now;
        ospf6_lsdb_add(lsa, lsa->lsdb);
 
+       if (ntohs(lsa->header->type) == OSPF6_LSTYPE_TYPE_7) {
+               area = OSPF6_AREA(lsa->lsdb->data);
+               ospf6_translated_nssa_refresh(area, lsa, NULL);
+               ospf6_schedule_abr_task(area->ospf6);
+       }
+
+       if (ntohs(lsa->header->type) == OSPF6_LSTYPE_ROUTER) {
+               area = OSPF6_AREA(lsa->lsdb->data);
+               if (old == NULL) {
+                       if (IS_OSPF6_DEBUG_LSA_TYPE(lsa->header->type)
+                           || IS_OSPF6_DEBUG_EXAMIN_TYPE(lsa->header->type))
+                               zlog_debug("%s: New router LSA %s", __func__,
+                                          lsa->name);
+                       ospf6_abr_nssa_check_status(area->ospf6);
+               }
+       }
        return;
 }
 
@@ -370,7 +394,8 @@ void ospf6_flood_interface(struct ospf6_neighbor *from, struct ospf6_lsa *lsa,
                        continue;
                }
 
-               if (oi->area->ospf6->inst_shutdown) {
+               if ((oi->area->ospf6->inst_shutdown)
+                   || CHECK_FLAG(lsa->flag, OSPF6_LSA_FLUSH)) {
                        if (is_debug)
                                zlog_debug(
                                        "%s: Send LSA %s (age %d) update now",
@@ -486,7 +511,12 @@ static void ospf6_flood_process(struct ospf6_neighbor *from,
                        continue;
 
                if (ntohs(lsa->header->type) == OSPF6_LSTYPE_AS_EXTERNAL
-                   && IS_AREA_STUB(oa))
+                   && (IS_AREA_STUB(oa) || IS_AREA_NSSA(oa)))
+                       continue;
+
+               /* Check for NSSA LSA */
+               if (ntohs(lsa->header->type) == OSPF6_LSTYPE_TYPE_7
+                   && !IS_AREA_NSSA(oa) && !OSPF6_LSA_IS_MAXAGE(lsa))
                        continue;
 
                ospf6_flood_area(from, lsa, oa);
@@ -526,7 +556,7 @@ static void ospf6_flood_clear_interface(struct ospf6_lsa *lsa,
        }
 }
 
-static void ospf6_flood_clear_area(struct ospf6_lsa *lsa, struct ospf6_area *oa)
+void ospf6_flood_clear_area(struct ospf6_lsa *lsa, struct ospf6_area *oa)
 {
        struct listnode *node, *nnode;
        struct ospf6_interface *oi;
@@ -555,7 +585,11 @@ static void ospf6_flood_clear_process(struct ospf6_lsa *lsa,
                        continue;
 
                if (ntohs(lsa->header->type) == OSPF6_LSTYPE_AS_EXTERNAL
-                   && IS_AREA_STUB(oa))
+                   && (IS_AREA_STUB(oa) || (IS_AREA_NSSA(oa))))
+                       continue;
+               /* Check for NSSA LSA */
+               if (ntohs(lsa->header->type) == OSPF6_LSTYPE_TYPE_7
+                   && !IS_AREA_NSSA(oa))
                        continue;
 
                ospf6_flood_clear_area(lsa, oa);
@@ -567,6 +601,8 @@ void ospf6_flood_clear(struct ospf6_lsa *lsa)
        struct ospf6 *ospf6;
 
        ospf6 = ospf6_get_by_lsdb(lsa);
+       if (ospf6 == NULL)
+               return;
        ospf6_flood_clear_process(lsa, ospf6);
 }
 
index 6931024fff43d0a74202a39a84113fe28dbd1cfc..5515a1c3feac8ada7e0e4571961267c5b9e96e1a 100644 (file)
@@ -67,4 +67,6 @@ extern void ospf6_flood_interface(struct ospf6_neighbor *from,
 extern int ospf6_lsupdate_send_neighbor_now(struct ospf6_neighbor *on,
                                            struct ospf6_lsa *lsa);
 
+extern void ospf6_flood_clear_area(struct ospf6_lsa *lsa,
+                                  struct ospf6_area *oa);
 #endif /* OSPF6_FLOOD_H */
index f037ea1f4dbc0669713a5446fd69df89fe374e7e..b71d884fdc4c1c616d6fa10f8266856dee2a94e2 100644 (file)
@@ -1197,6 +1197,26 @@ static int ospf6_interface_show(struct vty *vty, struct interface *ifp,
        return 0;
 }
 
+/* Find the global address to be used as a forwarding address in NSSA LSA.*/
+struct in6_addr *ospf6_interface_get_global_address(struct interface *ifp)
+{
+       struct listnode *n;
+       struct connected *c;
+       struct in6_addr *l = (struct in6_addr *)NULL;
+
+       /* for each connected address */
+       for (ALL_LIST_ELEMENTS_RO(ifp->connected, n, c)) {
+               /* if family not AF_INET6, ignore */
+               if (c->address->family != AF_INET6)
+                       continue;
+
+               if (!IN6_IS_ADDR_LINKLOCAL(&c->address->u.prefix6))
+                       l = &c->address->u.prefix6;
+       }
+       return l;
+}
+
+
 static int show_ospf6_interface_common(struct vty *vty, vrf_id_t vrf_id,
                                       int argc, struct cmd_token **argv,
                                       int idx_ifname, int intf_idx,
index 48b2cbff7402e5a72a1020867f0ee28e2bceff92..fb1b947cf8e37848dccc7508d52f93b02540fa6c 100644 (file)
@@ -189,6 +189,8 @@ extern void ospf6_interface_if_add(struct interface *);
 extern void ospf6_interface_state_update(struct interface *);
 extern void ospf6_interface_connected_route_update(struct interface *);
 extern void ospf6_interface_connected_route_add(struct connected *);
+extern struct in6_addr *
+ospf6_interface_get_global_address(struct interface *ifp);
 
 /* interface event */
 extern int interface_up(struct thread *);
index 12d11d45c1cac5bce1d27ad2b9c35f4fea5c3c83..68ff7548cb597206daea70c2855fe71b175ef6ef 100644 (file)
@@ -193,6 +193,17 @@ static void ospf6_router_lsa_options_set(struct ospf6_area *oa,
                UNSET_FLAG(router_lsa->bits, OSPF6_ROUTER_BIT_E);
        }
 
+       /* If the router is ASBR and the area-type is NSSA set the
+        * translate bit in router LSA.
+        */
+       if (IS_AREA_NSSA(oa)
+           && (ospf6_asbr_is_asbr(oa->ospf6) || IS_OSPF6_ABR(oa->ospf6))) {
+               if (oa->NSSATranslatorRole == OSPF6_NSSA_ROLE_ALWAYS)
+                       SET_FLAG(router_lsa->bits, OSPF6_ROUTER_BIT_NT);
+       } else {
+               UNSET_FLAG(router_lsa->bits, OSPF6_ROUTER_BIT_NT);
+       }
+
        UNSET_FLAG(router_lsa->bits, OSPF6_ROUTER_BIT_V);
        UNSET_FLAG(router_lsa->bits, OSPF6_ROUTER_BIT_W);
 }
@@ -2167,8 +2178,8 @@ void ospf6_intra_brouter_calculation(struct ospf6_area *oa)
 
        if (IS_OSPF6_DEBUG_BROUTER_SPECIFIC_AREA_ID(oa->area_id) ||
            IS_OSPF6_DEBUG_ROUTE(MEMORY))
-               zlog_info("%s: border-router calculation for area %s", __func__,
-                         oa->name);
+               zlog_debug("%s: border-router calculation for area %s",
+                          __func__, oa->name);
 
        hook_add = oa->ospf6->brouter_table->hook_add;
        hook_remove = oa->ospf6->brouter_table->hook_remove;
@@ -2189,8 +2200,8 @@ void ospf6_intra_brouter_calculation(struct ospf6_area *oa)
 
                if (IS_OSPF6_DEBUG_BROUTER_SPECIFIC_ROUTER_ID(brouter_id)
                    || IS_OSPF6_DEBUG_ROUTE(MEMORY)) {
-                       zlog_info("%p: mark as removing: area %s brouter %s",
-                                 (void *)brouter, oa->name, brouter_name);
+                       zlog_debug("%p: mark as removing: area %s brouter %s",
+                                  (void *)brouter, oa->name, brouter_name);
                        ospf6_brouter_debug_print(brouter);
                }
        }
@@ -2223,8 +2234,8 @@ void ospf6_intra_brouter_calculation(struct ospf6_area *oa)
 
                if (IS_OSPF6_DEBUG_BROUTER_SPECIFIC_ROUTER_ID(brouter_id)
                    || IS_OSPF6_DEBUG_ROUTE(MEMORY)) {
-                       zlog_info("%p: transfer: area %s brouter %s",
-                                 (void *)brouter, oa->name, brouter_name);
+                       zlog_debug("%p: transfer: area %s brouter %s",
+                                  (void *)brouter, oa->name, brouter_name);
                        ospf6_brouter_debug_print(brouter);
                }
        }
@@ -2297,7 +2308,7 @@ void ospf6_intra_brouter_calculation(struct ospf6_area *oa)
                                       brouter_id)
                            || IS_OSPF6_DEBUG_BROUTER_SPECIFIC_AREA_ID(
                                       oa->area_id))
-                               zlog_info(
+                               zlog_debug(
                                        "%s: brouter %s disappears via area %s",
                                        __func__, brouter_name, oa->name);
                        /* This is used to protect nbrouter from removed from
@@ -2325,8 +2336,9 @@ void ospf6_intra_brouter_calculation(struct ospf6_area *oa)
                                    brouter_id)
                            || IS_OSPF6_DEBUG_BROUTER_SPECIFIC_AREA_ID(
                                       oa->area_id))
-                               zlog_info("brouter %s still exists via area %s",
-                                         brouter_name, oa->name);
+                               zlog_debug(
+                                       "brouter %s still exists via area %s",
+                                       brouter_name, oa->name);
                        /* But re-originate summaries */
                        ospf6_abr_originate_summary(brouter, oa->ospf6);
                }
@@ -2341,8 +2353,8 @@ void ospf6_intra_brouter_calculation(struct ospf6_area *oa)
 
        if (IS_OSPF6_DEBUG_BROUTER_SPECIFIC_AREA_ID(oa->area_id) ||
            IS_OSPF6_DEBUG_ROUTE(MEMORY))
-               zlog_info("%s: border-router calculation for area %s: done",
-                         __func__, oa->name);
+               zlog_debug("%s: border-router calculation for area %s: done",
+                          __func__, oa->name);
 }
 
 static struct ospf6_lsa_handler router_handler = {
index f5f429b041dc1bd372bc3c14686a0cdc552183b2..c97ad749819f9665325e08555f13a595a05293b8 100644 (file)
@@ -458,6 +458,7 @@ void ospf6_lsa_show_summary(struct vty *vty, struct ospf6_lsa *lsa,
        case OSPF6_LSTYPE_INTER_PREFIX:
        case OSPF6_LSTYPE_INTER_ROUTER:
        case OSPF6_LSTYPE_AS_EXTERNAL:
+       case OSPF6_LSTYPE_TYPE_7:
                if (use_json) {
                        json_object_string_add(
                                json_obj, "type",
@@ -486,7 +487,6 @@ void ospf6_lsa_show_summary(struct vty *vty, struct ospf6_lsa *lsa,
        case OSPF6_LSTYPE_ROUTER:
        case OSPF6_LSTYPE_NETWORK:
        case OSPF6_LSTYPE_GROUP_MEMBERSHIP:
-       case OSPF6_LSTYPE_TYPE_7:
        case OSPF6_LSTYPE_LINK:
        case OSPF6_LSTYPE_INTRA_PREFIX:
                while (handler->lh_get_prefix_str(lsa, buf, sizeof(buf), cnt)
index 84c3b856311aeb83011ae4a02b208167bc0ecc4a..15b0d4ebbc8a845258e621075d9f970a858e5be3 100644 (file)
 #define OSPF6_SCOPE_AS         0x4000
 #define OSPF6_SCOPE_RESERVED   0x6000
 
+/* AS-external-LSA refresh method. */
+#define LSA_REFRESH_IF_CHANGED  0
+#define LSA_REFRESH_FORCE       1
+
+
 /* XXX U-bit handling should be treated here */
 #define OSPF6_LSA_SCOPE(type) (ntohs(type) & OSPF6_LSTYPE_SCOPE_MASK)
 
@@ -113,6 +118,7 @@ struct ospf6_lsa_header {
 #define OSPF6_LSA_IS_CHANGED(L1, L2) ospf6_lsa_is_changed (L1, L2)
 #define OSPF6_LSA_IS_SEQWRAP(L) ((L)->header->seqnum == htonl(OSPF_MAX_SEQUENCE_NUMBER + 1))
 
+
 struct ospf6_lsa {
        char name[64]; /* dump string */
 
@@ -133,6 +139,8 @@ struct ospf6_lsa {
 
        struct ospf6_lsdb *lsdb;
 
+       in_addr_t external_lsa_id;
+
        /* lsa instance */
        struct ospf6_lsa_header *header;
 };
@@ -143,6 +151,7 @@ struct ospf6_lsa {
 #define OSPF6_LSA_IMPLIEDACK 0x08
 #define OSPF6_LSA_UNAPPROVED 0x10
 #define OSPF6_LSA_SEQWRAPPED 0x20
+#define OSPF6_LSA_FLUSH      0x40
 
 struct ospf6_lsa_handler {
        uint16_t lh_type; /* host byte order */
index 18f121e3a2bc4f6405081bd09ac87b17f6df4ddd..304f03fde8a8373783d1b6a4ebbbccbc550fa35e 100644 (file)
@@ -320,9 +320,17 @@ int ospf6_lsdb_maxage_remover(struct ospf6_lsdb *lsdb)
        struct ospf6_lsa *lsa, *lsanext;
 
        for (ALL_LSDB(lsdb, lsa, lsanext)) {
-               if (!OSPF6_LSA_IS_MAXAGE(lsa))
+               if (!OSPF6_LSA_IS_MAXAGE(lsa)) {
+                       if (IS_OSPF6_DEBUG_LSA_TYPE(lsa->header->type))
+                               zlog_debug("Not MaxAge %s", lsa->name);
                        continue;
+               }
+
                if (lsa->retrans_count != 0) {
+                       if (IS_OSPF6_DEBUG_LSA_TYPE(lsa->header->type))
+                               zlog_debug("Remove MaxAge %s retrans_count %d",
+                                          lsa->name, lsa->retrans_count);
+
                        reschedule = 1;
                        continue;
                }
@@ -341,6 +349,7 @@ int ospf6_lsdb_maxage_remover(struct ospf6_lsdb *lsdb)
                        THREAD_OFF(lsa->refresh);
                        thread_execute(master, ospf6_lsa_refresh, lsa, 0);
                } else {
+                       zlog_debug("calling ospf6_lsdb_remove %s", lsa->name);
                        ospf6_lsdb_remove(lsa, lsdb);
                }
        }
diff --git a/ospf6d/ospf6_nssa.c b/ospf6d/ospf6_nssa.c
new file mode 100644 (file)
index 0000000..4d9b0a1
--- /dev/null
@@ -0,0 +1,1396 @@
+/*
+ * OSPFv3 Not So Stubby Area implementation.
+ *
+ * Copyright (C) 2021 Kaushik Nath
+ * Copyright (C) 2021 Soman K.S
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include <zebra.h>
+#include "log.h"
+#include "prefix.h"
+#include "table.h"
+#include "vty.h"
+#include "linklist.h"
+#include "command.h"
+#include "thread.h"
+#include "plist.h"
+#include "filter.h"
+
+#include "ospf6_proto.h"
+#include "ospf6_route.h"
+#include "ospf6_lsa.h"
+#include "ospf6_route.h"
+#include "ospf6_lsdb.h"
+#include "ospf6_message.h"
+#include "ospf6_zebra.h"
+
+#include "ospf6_top.h"
+#include "ospf6_area.h"
+#include "ospf6_interface.h"
+#include "ospf6_neighbor.h"
+
+#include "ospf6_flood.h"
+#include "ospf6_intra.h"
+#include "ospf6_abr.h"
+#include "ospf6_asbr.h"
+#include "ospf6d.h"
+#include "ospf6_nssa.h"
+
+DEFINE_MTYPE_STATIC(OSPF6D, OSPF6_LSA,         "OSPF6 LSA");
+unsigned char config_debug_ospf6_nssa = 0;
+/* Determine whether this router is elected translator or not for area */
+static int ospf6_abr_nssa_am_elected(struct ospf6_area *oa)
+{
+       struct ospf6_lsa *lsa;
+       struct ospf6_router_lsa *router_lsa;
+       in_addr_t *best = NULL;
+       uint16_t type;
+
+       type = htons(OSPF6_LSTYPE_ROUTER);
+
+       /* Verify all the router LSA to compare the router ID */
+       for (ALL_LSDB_TYPED(oa->lsdb, type, lsa)) {
+
+               router_lsa = (struct ospf6_router_lsa
+                                     *)((caddr_t)lsa->header
+                                        + sizeof(struct ospf6_lsa_header));
+
+               /* ignore non-ABR routers */
+               if (!CHECK_FLAG(router_lsa->bits, OSPF6_ROUTER_BIT_B))
+                       continue;
+
+               /* Router has Nt flag - always translate */
+               if (CHECK_FLAG(router_lsa->bits, OSPF6_ROUTER_BIT_NT)) {
+                       if (IS_OSPF6_DEBUG_NSSA)
+                               zlog_debug("%s: router %pI4 asserts Nt",
+                                          __func__, &lsa->header->id);
+                       return 1;
+               }
+
+               if (best == NULL)
+                       best = &lsa->header->adv_router;
+               else if (IPV4_ADDR_CMP(best, &lsa->header->adv_router) < 0)
+                       best = &lsa->header->adv_router;
+       }
+
+       if (best == NULL) {
+               if (IS_OSPF6_DEBUG_NSSA)
+                       zlog_debug("%s: best electable ABR not found",
+                                  __func__);
+               return 0;
+       }
+
+       if (IS_OSPF6_DEBUG_NSSA)
+               zlog_debug("%s: best electable ABR is: %pI4", __func__, best);
+
+       if (IPV4_ADDR_CMP(best, &oa->ospf6->router_id) <= 0) {
+               if (IS_OSPF6_DEBUG_NSSA)
+                       zlog_debug("%s: elected ABR is: %pI4", __func__, best);
+               return 1;
+       } else {
+               if (IS_OSPF6_DEBUG_NSSA)
+                       zlog_debug("%s: not elected best %pI4, router ID %pI4",
+                                  __func__, best, &oa->ospf6->router_id);
+               return 0;
+       }
+}
+
+/* Flush the translated LSA when translation is disabled */
+static void ospf6_flush_translated_lsa(struct ospf6_area *area)
+{
+       uint16_t type;
+       struct ospf6_lsa *type7;
+       struct ospf6_lsa *type5;
+       struct ospf6 *ospf6 = area->ospf6;
+
+       if (IS_OSPF6_DEBUG_NSSA)
+               zlog_debug("%s: start area %s", __func__, area->name);
+
+       type = htons(OSPF6_LSTYPE_TYPE_7);
+       for (ALL_LSDB_TYPED_ADVRTR(area->lsdb, type, ospf6->router_id, type7)) {
+               type5 = ospf6_lsdb_lookup(htons(OSPF6_LSTYPE_AS_EXTERNAL),
+                                         type7->external_lsa_id,
+                                         ospf6->router_id, ospf6->lsdb);
+               if (type5 && CHECK_FLAG(type5->flag, OSPF6_LSA_LOCAL_XLT))
+                       ospf6_lsa_premature_aging(type5);
+       }
+       if (IS_OSPF6_DEBUG_NSSA)
+               zlog_debug("%s: finish area %s", __func__, area->name);
+}
+
+/* Check NSSA status for all nssa areas*/
+void ospf6_abr_nssa_check_status(struct ospf6 *ospf6)
+{
+       struct ospf6_area *area;
+       struct listnode *lnode, *nnode;
+
+       for (ALL_LIST_ELEMENTS(ospf6->area_list, lnode, nnode, area)) {
+
+               if (IS_OSPF6_DEBUG_NSSA)
+                       zlog_debug("%s: checking area %s flag %x", __func__,
+                                  area->name, area->flag);
+
+               if (!IS_AREA_NSSA(area))
+                       continue;
+
+               if (!CHECK_FLAG(area->ospf6->flag, OSPF6_FLAG_ABR)) {
+                       if (IS_OSPF6_DEBUG_NSSA)
+                               zlog_debug("%s: not ABR", __func__);
+                       area->NSSATranslatorState =
+                               OSPF6_NSSA_TRANSLATE_DISABLED;
+                       ospf6_flush_translated_lsa(area);
+               } else {
+                       /* Router is ABR */
+                       if (area->NSSATranslatorRole == OSPF6_NSSA_ROLE_ALWAYS)
+                               area->NSSATranslatorState =
+                                       OSPF6_NSSA_TRANSLATE_ENABLED;
+                       else {
+                               /* We are a candidate for Translation */
+                               if (ospf6_abr_nssa_am_elected(area) > 0) {
+                                       area->NSSATranslatorState =
+                                               OSPF6_NSSA_TRANSLATE_ENABLED;
+                                       if (IS_OSPF6_DEBUG_NSSA)
+                                               zlog_debug(
+                                                       "%s: elected translator",
+                                                       __func__);
+                               } else {
+                                       area->NSSATranslatorState =
+                                               OSPF6_NSSA_TRANSLATE_DISABLED;
+                                       ospf6_flush_translated_lsa(area);
+                                       if (IS_OSPF6_DEBUG_NSSA)
+                                               zlog_debug("%s: not elected",
+                                                          __func__);
+                               }
+                       }
+               }
+       }
+       /* RFC3101, 3.1:
+        * All NSSA border routers must set the E-bit in the Type-1
+        * router-LSAs of their directly attached non-stub areas, even
+        * when they are not translating.
+        */
+       if (CHECK_FLAG(ospf6->flag, OSPF6_FLAG_ABR) && (ospf6->anyNSSA))
+               ospf6_asbr_status_update(ospf6, ++ospf6->redist_count);
+       else
+               ospf6_asbr_status_update(ospf6, --ospf6->redist_count);
+}
+
+/* Mark the summary LSA's as unapproved, when ABR status changes.*/
+static void ospf6_abr_unapprove_summaries(struct ospf6 *ospf6)
+{
+       struct listnode *node, *nnode;
+       struct ospf6_area *area;
+       struct ospf6_lsa *lsa;
+       uint16_t type;
+
+       if (IS_OSPF6_DEBUG_ABR)
+               zlog_debug("%s : Start", __func__);
+
+       for (ALL_LIST_ELEMENTS(ospf6->area_list, node, nnode, area)) {
+               if (IS_OSPF6_DEBUG_ABR)
+                       zlog_debug("%s : considering area %pI4", __func__,
+                                  &area->area_id);
+               /* Inter area router LSA */
+               type = htons(OSPF6_LSTYPE_INTER_ROUTER);
+               for (ALL_LSDB_TYPED_ADVRTR(area->lsdb, type, ospf6->router_id,
+                                          lsa)) {
+                       if (IS_OSPF6_DEBUG_ABR)
+                               zlog_debug(
+                                       "%s : approved unset on summary link id %pI4",
+                                       __func__, &lsa->header->id);
+                       SET_FLAG(lsa->flag, OSPF6_LSA_UNAPPROVED);
+               }
+               /* Inter area prefix LSA */
+               type = htons(OSPF6_LSTYPE_INTER_PREFIX);
+               for (ALL_LSDB_TYPED_ADVRTR(area->lsdb, type, ospf6->router_id,
+                                          lsa)) {
+                       if (IS_OSPF6_DEBUG_ABR)
+                               zlog_debug(
+                                       "%s : approved unset on asbr-summary link id %pI4",
+                                       __func__, &lsa->header->id);
+                       SET_FLAG(lsa->flag, OSPF6_LSA_UNAPPROVED);
+               }
+       }
+
+       if (IS_OSPF6_DEBUG_ABR)
+               zlog_debug("%s : Stop", __func__);
+}
+
+/* Re-advertise inter-area router LSA's */
+void ospf6_asbr_prefix_readvertise(struct ospf6 *ospf6)
+{
+       struct ospf6_route *brouter;
+       struct listnode *node, *nnode;
+       struct ospf6_area *oa;
+
+       if (IS_OSPF6_DEBUG_ABR)
+               zlog_debug("Re-examining Inter-Router prefixes");
+
+
+       for (ALL_LIST_ELEMENTS(ospf6->area_list, node, nnode, oa)) {
+               for (brouter = ospf6_route_head(oa->ospf6->brouter_table);
+                    brouter; brouter = ospf6_route_next(brouter))
+                       ospf6_abr_originate_summary_to_area(brouter, oa);
+       }
+
+       if (IS_OSPF6_DEBUG_ABR)
+               zlog_debug("Finished re-examining Inter-Router prefixes");
+}
+
+/* Advertise prefixes configured using area <area-id> range command */
+static void ospf6_abr_announce_aggregates(struct ospf6 *ospf6)
+{
+       struct ospf6_area *area;
+       struct ospf6_route *range;
+       struct listnode *node, *nnode;
+
+       if (IS_OSPF6_DEBUG_ABR)
+               zlog_debug("ospf6_abr_announce_aggregates(): Start");
+
+       for (ALL_LIST_ELEMENTS(ospf6->area_list, node, nnode, area)) {
+               for (range = ospf6_route_head(area->range_table); range;
+                    range = ospf6_route_next(range))
+                       ospf6_abr_range_update(range, ospf6);
+       }
+
+       for (ALL_LIST_ELEMENTS_RO(ospf6->area_list, node, area)) {
+               if (IS_OSPF6_DEBUG_ABR)
+                       zlog_debug(
+                               "ospf_abr_announce_aggregates(): looking at area %pI4",
+                               &area->area_id);
+       }
+
+       if (IS_OSPF6_DEBUG_ABR)
+               zlog_debug("ospf6_abr_announce_aggregates(): Stop");
+}
+
+/* Flush the summary LSA's which are not approved.*/
+void ospf6_abr_remove_unapproved_summaries(struct ospf6 *ospf6)
+{
+       struct listnode *node, *nnode;
+       struct ospf6_area *area;
+       struct ospf6_lsa *lsa;
+       uint16_t type;
+
+       if (IS_OSPF6_DEBUG_ABR)
+               zlog_debug("%s : Start", __func__);
+
+       for (ALL_LIST_ELEMENTS(ospf6->area_list, node, nnode, area)) {
+               if (IS_OSPF6_DEBUG_ABR)
+                       zlog_debug("%s : looking at area %pI4", __func__,
+                                  &area->area_id);
+
+               /* Inter area router LSA */
+               type = htons(OSPF6_LSTYPE_INTER_ROUTER);
+               for (ALL_LSDB_TYPED_ADVRTR(area->lsdb, type, ospf6->router_id,
+                                          lsa)) {
+                       if (CHECK_FLAG(lsa->flag, OSPF6_LSA_UNAPPROVED)) {
+                               lsa->header->age = htons(OSPF_LSA_MAXAGE);
+                               THREAD_OFF(lsa->refresh);
+                               thread_execute(master, ospf6_lsa_expire, lsa,
+                                              0);
+                       }
+               }
+
+               /* Inter area prefix LSA */
+               type = htons(OSPF6_LSTYPE_INTER_PREFIX);
+               for (ALL_LSDB_TYPED_ADVRTR(area->lsdb, type, ospf6->router_id,
+                                          lsa)) {
+                       if (CHECK_FLAG(lsa->flag, OSPF6_LSA_UNAPPROVED)) {
+                               lsa->header->age = htons(OSPF_LSA_MAXAGE);
+                               THREAD_OFF(lsa->refresh);
+                               thread_execute(master, ospf6_lsa_expire, lsa,
+                                              0);
+                       }
+               }
+       }
+
+       if (IS_OSPF6_DEBUG_ABR)
+               zlog_debug("%s : Stop", __func__);
+}
+
+/*
+ * This is the function taking care about ABR stuff, i.e.
+ * summary-LSA origination and flooding.
+ */
+static void ospf6_abr_task(struct ospf6 *ospf6)
+{
+       if (IS_OSPF6_DEBUG_ABR)
+               zlog_debug("%s : Start", __func__);
+
+       if (ospf6->route_table == NULL || ospf6->brouter_table == NULL) {
+               if (IS_OSPF6_DEBUG_ABR)
+                       zlog_debug("%s : Routing tables are not yet ready",
+                                  __func__);
+               return;
+       }
+
+       ospf6_abr_unapprove_summaries(ospf6);
+
+       if (IS_OSPF6_DEBUG_ABR)
+               zlog_debug("%s : prepare aggregates", __func__);
+
+       ospf6_abr_range_reset_cost(ospf6);
+
+       if (IS_OSPF6_ABR(ospf6)) {
+               if (IS_OSPF6_DEBUG_ABR)
+                       zlog_debug("%s : process network RT", __func__);
+               ospf6_abr_prefix_resummarize(ospf6);
+
+               if (IS_OSPF6_DEBUG_ABR)
+                       zlog_debug("%s : process router RT", __func__);
+               ospf6_asbr_prefix_readvertise(ospf6);
+
+               if (IS_OSPF6_DEBUG_ABR)
+                       zlog_debug("%s : announce aggregates", __func__);
+               ospf6_abr_announce_aggregates(ospf6);
+
+               if (IS_OSPF6_DEBUG_ABR)
+                       zlog_debug("%s : announce stub defaults", __func__);
+               ospf6_abr_defaults_to_stub(ospf6);
+       }
+
+       if (IS_OSPF6_DEBUG_ABR)
+               zlog_debug("%s : remove unapproved summaries", __func__);
+       ospf6_abr_remove_unapproved_summaries(ospf6);
+
+       if (IS_OSPF6_DEBUG_ABR)
+               zlog_debug("%s : Stop", __func__);
+}
+
+/* For NSSA Translations
+ * Mark the translated LSA's as unapproved. */
+static void ospf6_abr_unapprove_translates(struct ospf6 *ospf6)
+{
+       struct ospf6_lsa *lsa;
+       uint16_t type;
+       struct ospf6_area *oa;
+       struct listnode *node;
+
+       if (IS_OSPF6_DEBUG_NSSA)
+               zlog_debug("ospf6_abr_unapprove_translates(): Start");
+
+       type = htons(OSPF6_LSTYPE_AS_EXTERNAL);
+       for (ALL_LIST_ELEMENTS_RO(ospf6->area_list, node, oa)) {
+               for (ALL_LSDB_TYPED(oa->lsdb, type, lsa)) {
+                       if (CHECK_FLAG(lsa->flag, OSPF6_LSA_LOCAL_XLT)) {
+                               SET_FLAG(lsa->flag, OSPF6_LSA_UNAPPROVED);
+                               if (IS_OSPF6_DEBUG_NSSA)
+                                       zlog_debug(
+                                               "%s : approved unset on link id %pI4",
+                                               __func__, &lsa->header->id);
+                       }
+               }
+       }
+
+       if (IS_OSPF6_DEBUG_NSSA)
+               zlog_debug("ospf6_abr_unapprove_translates(): Stop");
+}
+
+/* Generate the translated external lsa  from NSSA lsa */
+static struct ospf6_lsa *ospf6_lsa_translated_nssa_new(struct ospf6_area *area,
+                                                      struct ospf6_lsa *type7)
+{
+       char *buffer;
+       struct ospf6_lsa *lsa;
+       struct ospf6_as_external_lsa *ext, *extnew;
+       struct ospf6_lsa_header *lsa_header;
+       caddr_t old_ptr, new_ptr;
+       struct ospf6_as_external_lsa *nssa;
+       struct prefix prefix;
+       struct ospf6_route *match;
+       struct ospf6 *ospf6 = area->ospf6;
+       ptrdiff_t tag_offset = 0;
+       route_tag_t network_order;
+
+       if (IS_OSPF6_DEBUG_NSSA)
+               zlog_debug("%s : Start", __func__);
+
+       if (area->NSSATranslatorState == OSPF6_NSSA_TRANSLATE_DISABLED) {
+               if (IS_OSPF6_DEBUG_NSSA)
+                       zlog_debug("%s: Translation disabled for area %s",
+                                  __func__, area->name);
+               return NULL;
+       }
+
+       buffer = XCALLOC(MTYPE_OSPF6_LSA, OSPF6_MAX_LSASIZE);
+       lsa_header = (struct ospf6_lsa_header *)buffer;
+       extnew = (struct ospf6_as_external_lsa
+                         *)((caddr_t)lsa_header
+                            + sizeof(struct ospf6_lsa_header));
+       ext = (struct ospf6_as_external_lsa
+                      *)((caddr_t)(type7->header)
+                         + sizeof(struct ospf6_lsa_header));
+       old_ptr =
+               (caddr_t)((caddr_t)ext + sizeof(struct ospf6_as_external_lsa));
+       new_ptr = (caddr_t)((caddr_t)extnew
+                           + sizeof(struct ospf6_as_external_lsa));
+
+       memcpy(extnew, ext, sizeof(struct ospf6_as_external_lsa));
+
+       /* find the translated Type-5 for this Type-7 */
+       nssa = (struct ospf6_as_external_lsa *)OSPF6_LSA_HEADER_END(
+               type7->header);
+
+       prefix.family = AF_INET6;
+       prefix.prefixlen = nssa->prefix.prefix_length;
+       ospf6_prefix_in6_addr(&prefix.u.prefix6, nssa, &nssa->prefix);
+
+       /* Find the LSA from the external route */
+       match = ospf6_route_lookup(&prefix, area->route_table);
+       if (match == NULL) {
+               if (IS_OSPF6_DEBUG_NSSA)
+                       zlog_debug("%s : no matching route %pFX", __func__,
+                                  &prefix);
+               return NULL;
+       }
+
+       /* set Prefix */
+       memcpy(new_ptr, old_ptr, OSPF6_PREFIX_SPACE(ext->prefix.prefix_length));
+       ospf6_prefix_apply_mask(&extnew->prefix);
+       new_ptr += OSPF6_PREFIX_SPACE(extnew->prefix.prefix_length);
+
+       tag_offset =
+               sizeof(*ext) + OSPF6_PREFIX_SPACE(ext->prefix.prefix_length);
+
+       /* Forwarding address */
+       if (CHECK_FLAG(ext->bits_metric, OSPF6_ASBR_BIT_F)) {
+               memcpy(new_ptr, (caddr_t)ext + tag_offset,
+                      sizeof(struct in6_addr));
+               new_ptr += sizeof(struct in6_addr);
+               tag_offset += sizeof(struct in6_addr);
+       }
+       /* External Route Tag */
+       if (CHECK_FLAG(ext->bits_metric, OSPF6_ASBR_BIT_T)) {
+               memcpy(&network_order, (caddr_t)ext + tag_offset,
+                      sizeof(network_order));
+               network_order = htonl(network_order);
+               memcpy(new_ptr, &network_order, sizeof(network_order));
+               new_ptr += sizeof(network_order);
+       }
+
+       /* Fill LSA Header */
+       lsa_header->age = 0;
+       lsa_header->type = htons(OSPF6_LSTYPE_AS_EXTERNAL);
+       lsa_header->id = htonl(ospf6->external_id);
+       ospf6->external_id++;
+       lsa_header->adv_router = ospf6->router_id;
+       lsa_header->seqnum =
+               ospf6_new_ls_seqnum(lsa_header->type, lsa_header->id,
+                                   lsa_header->adv_router, ospf6->lsdb);
+       lsa_header->length = htons((caddr_t)new_ptr - (caddr_t)lsa_header);
+       type7->external_lsa_id = lsa_header->id;
+
+       /* LSA checksum */
+       ospf6_lsa_checksum(lsa_header);
+
+       /* create LSA */
+       lsa = ospf6_lsa_create(lsa_header);
+
+       SET_FLAG(lsa->flag, OSPF6_LSA_LOCAL_XLT);
+       UNSET_FLAG(lsa->flag, OSPF6_LSA_UNAPPROVED);
+
+       /* Originate */
+       ospf6_lsa_originate_process(lsa, ospf6);
+
+       if (IS_OSPF6_DEBUG_NSSA)
+               zlog_debug("%s: Originated type5 LSA id %pI4", __func__,
+                          &lsa_header->id);
+       return lsa;
+}
+
+/* Delete LSA from retransmission list */
+static void ospf6_ls_retransmit_delete_nbr_as(struct ospf6 *ospf6,
+                                             struct ospf6_lsa *lsa)
+{
+       struct listnode *node, *nnode;
+       struct ospf6_area *area;
+
+       if (IS_OSPF6_DEBUG_NSSA)
+               zlog_debug("%s : start lsa %s", __func__, lsa->name);
+
+       /*The function ospf6_flood_clear_area removes LSA from
+        * retransmit list.
+        */
+       for (ALL_LIST_ELEMENTS(ospf6->area_list, node, nnode, area))
+               ospf6_flood_clear_area(lsa, area);
+
+       if (IS_OSPF6_DEBUG_NSSA)
+               zlog_debug("%s : finish  lsa %s", __func__, lsa->name);
+}
+
+/* Refresh translated  AS-external-LSA. */
+struct ospf6_lsa *ospf6_translated_nssa_refresh(struct ospf6_area *area,
+                                               struct ospf6_lsa *type7,
+                                               struct ospf6_lsa *type5)
+{
+       struct ospf6_lsa *new = NULL;
+       struct ospf6_as_external_lsa *ext_lsa;
+       struct prefix prefix;
+       struct ospf6 *ospf6 = area->ospf6;
+
+       if (IS_OSPF6_DEBUG_NSSA)
+               zlog_debug("%s : start area %s", __func__, area->name);
+
+       /* Sanity checks. */
+       assert(type7);
+
+       /* Find the AS external LSA */
+       if (type5 == NULL) {
+               if (IS_OSPF6_DEBUG_NSSA)
+                       zlog_debug(
+                               "%s: No translated Type-5 found for Type-7 with Id %pI4",
+                               __func__, &type7->header->id);
+
+               /* find the translated Type-5 for this Type-7 */
+               ext_lsa = (struct ospf6_as_external_lsa *)OSPF6_LSA_HEADER_END(
+                       type7->header);
+
+               prefix.family = AF_INET6;
+               prefix.prefixlen = ext_lsa->prefix.prefix_length;
+               ospf6_prefix_in6_addr(&prefix.u.prefix6, ext_lsa,
+                                     &ext_lsa->prefix);
+
+               /* Find the AS external LSA from Type-7 LSA */
+               if (IS_OSPF6_DEBUG_NSSA)
+                       zlog_debug("%s: try to find external LSA id %d",
+                                  __func__, type7->external_lsa_id);
+               type5 = ospf6_lsdb_lookup(htons(OSPF6_LSTYPE_AS_EXTERNAL),
+                                         type7->external_lsa_id,
+                                         ospf6->router_id, ospf6->lsdb);
+       }
+
+       if (type5) {
+               if (CHECK_FLAG(type5->flag, OSPF6_LSA_LOCAL_XLT)) {
+                       /* Delete LSA from neighbor retransmit-list. */
+                       ospf6_ls_retransmit_delete_nbr_as(ospf6, type5);
+
+                       /* Flush the LSA */
+                       ospf6_lsa_premature_aging(type5);
+               } else {
+                       if (IS_OSPF6_DEBUG_NSSA)
+                               zlog_debug("%s: Invalid translated LSA %s",
+                                          __func__, type5->name);
+                       return NULL;
+               }
+       }
+
+       /* create new translated LSA */
+       if (ospf6_lsa_age_current(type7) != OSPF_LSA_MAXAGE) {
+               if ((new = ospf6_lsa_translated_nssa_new(area, type7))
+                   == NULL) {
+                       if (IS_OSPF6_DEBUG_NSSA)
+                               zlog_debug(
+                                       "%s: Could not translate Type-7 for %pI4",
+                                       __func__, &type7->header->id);
+                       return NULL;
+               }
+       }
+
+       if (IS_OSPF6_DEBUG_NSSA)
+               zlog_debug("%s: finish", __func__);
+
+       return new;
+}
+
+/* Originate Translated Type-5 for supplied Type-7 NSSA LSA */
+struct ospf6_lsa *ospf6_translated_nssa_originate(struct ospf6_area *oa,
+                                                 struct ospf6_lsa *type7)
+{
+       struct ospf6_lsa *new;
+
+       if (ntohs(type7->header->type) != OSPF6_LSTYPE_TYPE_7)
+               return NULL;
+
+       if ((new = ospf6_lsa_translated_nssa_new(oa, type7)) == NULL) {
+               if (IS_OSPF6_DEBUG_NSSA)
+                       zlog_debug(
+                               "%s : Could not translate Type-7, Id %pI4, to Type-5",
+                               __func__, &type7->header->id);
+               return NULL;
+       }
+
+       return new;
+}
+
+int ospf6_abr_translate_nssa(struct ospf6_area *area, struct ospf6_lsa *lsa)
+{
+       /* Incoming Type-7 or later aggregated Type-7
+        *
+        * LSA is skipped if P-bit is off.
+        * LSA is aggregated if within range.
+        *
+        * The Type-7 is translated, Installed/Approved as a Type-5 into
+        * global LSDB, then Flooded through AS
+        *
+        *  Later, any Unapproved Translated Type-5's are flushed/discarded
+        */
+
+       struct ospf6_lsa *old = NULL, *new = NULL;
+       struct ospf6_as_external_lsa *nssa_lsa;
+       struct prefix prefix;
+       struct ospf6_route *match;
+       struct ospf6 *ospf6;
+
+       ospf6 = area->ospf6;
+       nssa_lsa = (struct ospf6_as_external_lsa *)OSPF6_LSA_HEADER_END(
+               lsa->header);
+
+       if (!CHECK_FLAG(nssa_lsa->prefix.prefix_options,
+                       OSPF6_PREFIX_OPTION_P)) {
+               if (IS_OSPF6_DEBUG_NSSA)
+                       zlog_debug(
+                               "%s : LSA Id %pI4, P-bit off, NO Translation",
+                               __func__, &lsa->header->id);
+               return 1;
+       }
+
+       if (IS_OSPF6_DEBUG_NSSA)
+               zlog_debug(
+                       "%s : LSA Id %pI4 external ID %pI4, Translating type 7 to 5",
+                       __func__, &lsa->header->id, &lsa->external_lsa_id);
+
+       prefix.family = AF_INET6;
+       prefix.prefixlen = nssa_lsa->prefix.prefix_length;
+       ospf6_prefix_in6_addr(&prefix.u.prefix6, nssa_lsa, &nssa_lsa->prefix);
+
+       if (!CHECK_FLAG(nssa_lsa->bits_metric, OSPF6_ASBR_BIT_F)) {
+               if (IS_OSPF6_DEBUG_NSSA)
+                       zlog_debug(
+                               "%s : LSA Id %pI4, Forward address is 0, NO Translation",
+                               __func__, &lsa->header->id);
+               return 1;
+       }
+
+       /* Find the existing AS-External LSA for this prefix */
+       match = ospf6_route_lookup(&prefix, ospf6->external_table);
+       if (match) {
+               old = ospf6_lsdb_lookup(OSPF6_LSTYPE_AS_EXTERNAL,
+                                       match->path.origin.id, ospf6->router_id,
+                                       ospf6->lsdb);
+       }
+
+       /* Check Type 5 LSA using the matching external ID */
+       if (old == NULL) {
+               old = ospf6_lsdb_lookup(htons(OSPF6_LSTYPE_AS_EXTERNAL),
+                                       lsa->external_lsa_id, ospf6->router_id,
+                                       ospf6->lsdb);
+       }
+
+       if (old) {
+               /* Do not continue if type 5 LSA not approved */
+               if (CHECK_FLAG(old->flag, OSPF6_LSA_UNAPPROVED)) {
+                       if (IS_OSPF6_DEBUG_NSSA)
+                               zlog_debug(
+                                       "%s : LSA Id %pI4 type 5 is not approved",
+                                       __func__, &old->header->id);
+                       return 1;
+               }
+
+               if (IS_OSPF6_DEBUG_NSSA)
+                       zlog_debug(
+                               "%s : found old translated LSA Id %pI4, refreshing",
+                               __func__, &old->header->id);
+
+               /* refresh */
+               new = ospf6_translated_nssa_refresh(area, lsa, old);
+               if (!new) {
+                       if (IS_OSPF6_DEBUG_NSSA)
+                               zlog_debug(
+                                       "%s : could not refresh translated LSA Id %pI4",
+                                       __func__, &old->header->id);
+               }
+       } else {
+               /* no existing external route for this LSA Id
+                * originate translated LSA
+                */
+
+               if (ospf6_translated_nssa_originate(area, lsa) == NULL) {
+                       if (IS_OSPF6_DEBUG_NSSA)
+                               zlog_debug(
+                                       "%s : Could not translate Type-7 for %pI4 to Type-5",
+                                       __func__, &lsa->header->id);
+                       return 1;
+               }
+       }
+
+       return 0;
+}
+
+static void ospf6_abr_process_nssa_translates(struct ospf6 *ospf6)
+{
+       /* Scan through all NSSA_LSDB records for all areas;
+        * If P-bit is on, translate all Type-7's to 5's and aggregate or\
+        * flood install as approved in Type-5 LSDB with XLATE Flag on
+        * later, do same for all aggregates...  At end, DISCARD all
+        * remaining UNAPPROVED Type-5's (Aggregate is for future ) */
+
+       struct listnode *node;
+       struct ospf6_area *oa;
+       struct ospf6_lsa *lsa;
+       int type;
+
+       if (IS_OSPF6_DEBUG_NSSA)
+               zlog_debug("%s : Start", __func__);
+
+       for (ALL_LIST_ELEMENTS_RO(ospf6->area_list, node, oa)) {
+
+               /* skip if not translator */
+               if (oa->NSSATranslatorState == OSPF6_NSSA_TRANSLATE_DISABLED) {
+                       zlog_debug("%s area %pI4 NSSATranslatorState %d",
+                                  __func__, &oa->area_id,
+                                  oa->NSSATranslatorState);
+                       continue;
+               }
+
+               /* skip if not Nssa Area */
+               if (!IS_AREA_NSSA(oa)) {
+                       zlog_debug("%s area %pI4 Flag %x", __func__,
+                                  &oa->area_id, oa->flag);
+                       continue;
+               }
+
+               if (IS_OSPF6_DEBUG_NSSA)
+                       zlog_debug("%s : looking at area %pI4", __func__,
+                                  &oa->area_id);
+
+               type = htons(OSPF6_LSTYPE_TYPE_7);
+               for (ALL_LSDB_TYPED(oa->lsdb, type, lsa)) {
+                       zlog_debug("%s : lsa %s , id %pI4 , adv router %pI4",
+                                  lsa->name, __func__, &lsa->header->id,
+                                  &lsa->header->adv_router);
+                       ospf6_abr_translate_nssa(oa, lsa);
+               }
+       }
+
+       if (IS_OSPF6_DEBUG_NSSA)
+               zlog_debug("%s : Stop", __func__);
+}
+
+/* Generate translated type-5 LSA from the configured area ranges*/
+static void ospf6_abr_translate_nssa_range(struct ospf6 *ospf6)
+{
+       struct listnode *node, *nnode;
+       struct ospf6_area *oa;
+       struct ospf6_route *range;
+       struct ospf6_lsa *lsa;
+
+       for (ALL_LIST_ELEMENTS(ospf6->area_list, node, nnode, oa)) {
+               for (range = ospf6_route_head(oa->range_table); range;
+                    range = ospf6_route_next(range)) {
+                       if (IS_OSPF6_DEBUG_NSSA)
+                               zlog_debug(
+                                       "Translating range %pFX of area %pI4",
+                                       &range->prefix, &oa->area_id);
+                       if (CHECK_FLAG(range->flag,
+                                      OSPF6_ROUTE_DO_NOT_ADVERTISE))
+                               continue;
+
+                       /* Find the NSSA LSA from the route */
+                       /* Generate and flood external LSA */
+                       lsa = ospf6_lsdb_lookup(OSPF6_LSTYPE_TYPE_7,
+                                               range->path.origin.id,
+                                               ospf6->router_id, oa->lsdb);
+                       if (lsa)
+                               ospf6_abr_translate_nssa(oa, lsa);
+               }
+       }
+}
+
+static void ospf6_abr_send_nssa_aggregates(struct ospf6 *ospf6)
+{
+       struct listnode *node;
+       struct ospf6_area *area;
+
+       if (IS_OSPF6_DEBUG_NSSA)
+               zlog_debug("%s : Start", __func__);
+
+       for (ALL_LIST_ELEMENTS_RO(ospf6->area_list, node, area)) {
+               if (area->NSSATranslatorState == OSPF6_NSSA_TRANSLATE_DISABLED)
+                       continue;
+
+               if (IS_OSPF6_DEBUG_NSSA)
+                       zlog_debug("%s : looking at area %pI4", __func__,
+                                  &area->area_id);
+
+               ospf6_abr_translate_nssa_range(ospf6);
+       }
+
+       if (IS_OSPF6_DEBUG_NSSA)
+               zlog_debug("%s : Stop", __func__);
+}
+
+/*Flood max age LSA's for the unapproved LSA's */
+static int ospf6_abr_remove_unapproved_translates_apply(struct ospf6_lsa *lsa)
+{
+       if (CHECK_FLAG(lsa->flag, OSPF6_LSA_LOCAL_XLT)
+           && CHECK_FLAG(lsa->flag, OSPF6_LSA_UNAPPROVED)) {
+               zlog_debug("%s : removing unapproved translates, lsa : %s",
+                          __func__, lsa->name);
+
+               /* FLUSH THROUGHOUT AS */
+               ospf6_lsa_premature_aging(lsa);
+       }
+       return 0;
+}
+
+static void ospf6_abr_remove_unapproved_translates(struct ospf6 *ospf6)
+{
+       struct ospf6_lsa *lsa;
+       uint16_t type;
+
+       /* All AREA PROCESS should have APPROVED necessary LSAs */
+       /* Remove any left over and not APPROVED */
+       if (IS_OSPF6_DEBUG_NSSA)
+               zlog_debug("ospf6_abr_remove_unapproved_translates(): Start");
+
+       type = htons(OSPF6_LSTYPE_AS_EXTERNAL);
+       for (ALL_LSDB_TYPED(ospf6->lsdb, type, lsa))
+               ospf6_abr_remove_unapproved_translates_apply(lsa);
+
+       if (IS_OSPF6_DEBUG_NSSA)
+               zlog_debug("ospf_abr_remove_unapproved_translates(): Stop");
+}
+
+static void ospf6_abr_nssa_task(struct ospf6 *ospf6)
+{
+       /* called only if any_nssa */
+       struct ospf6_route *range;
+       struct ospf6_area *area;
+       struct listnode *node, *nnode;
+
+       if (IS_OSPF6_DEBUG_NSSA)
+               zlog_debug("Check for NSSA-ABR Tasks():");
+
+       if (!IS_OSPF6_ABR(ospf6)) {
+               if (IS_OSPF6_DEBUG_NSSA)
+                       zlog_debug("%s  Not ABR", __func__);
+               return;
+       }
+
+       if (!ospf6->anyNSSA) {
+               if (IS_OSPF6_DEBUG_NSSA)
+                       zlog_debug("%s  Not NSSA", __func__);
+               return;
+       }
+
+       /* Each area must confirm TranslatorRole */
+       if (IS_OSPF6_DEBUG_NSSA)
+               zlog_debug("ospf6_abr_nssa_task(): Start");
+
+       /* For all Global Entries flagged "local-translate", unset APPROVED */
+       if (IS_OSPF6_DEBUG_NSSA)
+               zlog_debug("ospf6_abr_nssa_task(): unapprove translates");
+
+       ospf6_abr_unapprove_translates(ospf6);
+
+       /* RESET all Ranges in every Area, same as summaries */
+       if (IS_OSPF6_DEBUG_NSSA)
+               zlog_debug("ospf6_abr_nssa_task(): NSSA initialize aggregates");
+       ospf6_abr_range_reset_cost(ospf6);
+
+       /* For all NSSAs, Type-7s, translate to 5's, INSTALL/FLOOD, or
+        *  Aggregate as Type-7
+        * Install or Approve in Type-5 Global LSDB
+        */
+       if (IS_OSPF6_DEBUG_NSSA)
+               zlog_debug("ospf6_abr_nssa_task(): process translates");
+       ospf6_abr_process_nssa_translates(ospf6);
+
+       /* Translate/Send any "ranged" aggregates, and also 5-Install and
+        *  Approve
+        * Scan Type-7's for aggregates, translate to Type-5's,
+        *  Install/Flood/Approve
+        */
+       if (IS_OSPF6_DEBUG_NSSA)
+               zlog_debug("ospf6_abr_nssa_task(): send NSSA aggregates");
+       ospf6_abr_send_nssa_aggregates(ospf6); /*TURNED OFF FOR NOW */
+
+       /* Flush any unapproved previous translates from Global Data Base */
+       if (IS_OSPF6_DEBUG_NSSA)
+               zlog_debug(
+                       "ospf6_abr_nssa_task(): remove unapproved translates");
+       ospf6_abr_remove_unapproved_translates(ospf6);
+
+       for (ALL_LIST_ELEMENTS(ospf6->area_list, node, nnode, area)) {
+               for (range = ospf6_route_head(area->range_table); range;
+                    range = ospf6_route_next(range)) {
+                       if (CHECK_FLAG(range->flag,
+                                      OSPF6_ROUTE_DO_NOT_ADVERTISE))
+                               ospf6_zebra_delete_discard(range, ospf6);
+                       else
+                               ospf6_zebra_add_discard(range, ospf6);
+               }
+       }
+
+       if (IS_OSPF6_DEBUG_NSSA)
+               zlog_debug("ospf6_abr_nssa_task(): Stop");
+}
+
+int ospf6_redistribute_check(struct ospf6 *ospf6, struct ospf6_route *route,
+                            int type)
+{
+       route_map_result_t ret;
+       struct prefix *prefix;
+       struct ospf6_redist *red;
+
+       if (!ospf6_zebra_is_redistribute(type, ospf6->vrf_id))
+               return 0;
+
+       prefix = &route->prefix;
+
+       red = ospf6_redist_lookup(ospf6, type, 0);
+       if (!red)
+               return 0;
+
+       /* Change to new redist structure */
+       if (ROUTEMAP_NAME(red)) {
+               if (ROUTEMAP(red) == NULL)
+                       ospf6_asbr_routemap_update(NULL);
+               if (ROUTEMAP(red) == NULL) {
+                       zlog_warn(
+                               "route-map \"%s\" not found, suppress redistributing",
+                               ROUTEMAP_NAME(red));
+                       return 0;
+               }
+       }
+
+       /*  Change to new redist structure */
+       if (ROUTEMAP(red)) {
+               ret = route_map_apply(ROUTEMAP(red), prefix, route);
+               if (ret == RMAP_DENYMATCH) {
+                       if (IS_OSPF6_DEBUG_ASBR)
+                               zlog_debug("Denied by route-map \"%s\"",
+                                          ROUTEMAP_NAME(red));
+                       return 0;
+               }
+       }
+
+       return 1;
+}
+
+static void ospf6_external_lsa_refresh_type(struct ospf6 *ospf6, uint8_t type,
+                                           unsigned short instance, int force)
+{
+       struct ospf6_route *route;
+       struct ospf6_external_info *info;
+       struct ospf6_lsa *lsa;
+
+       if (type == ZEBRA_ROUTE_MAX)
+               return;
+
+       for (route = ospf6_route_head(ospf6->external_table); route;
+            route = ospf6_route_next(route)) {
+               info = route->route_option;
+
+               /* Find the external LSA in the database */
+               if (!is_default_prefix(&route->prefix)) {
+                       lsa = ospf6_lsdb_lookup(htons(OSPF6_LSTYPE_AS_EXTERNAL),
+                                               htonl(info->id),
+                                               ospf6->router_id, ospf6->lsdb);
+
+                       if (lsa) {
+                               THREAD_OFF(lsa->refresh);
+
+                               /* LSA is maxage,  immediate refresh */
+                               if (OSPF6_LSA_IS_MAXAGE(lsa))
+                                       ospf6_flood(NULL, lsa);
+                               else
+                                       thread_add_timer(master,
+                                                        ospf6_lsa_refresh, lsa,
+                                                        OSPF_LS_REFRESH_TIME,
+                                                        &lsa->refresh);
+                       } else {
+                               /* LSA not found in the database
+                                * Verify and originate  external LSA
+                                */
+                               if (ospf6_redistribute_check(ospf6, route,
+                                                            type))
+                                       ospf6_as_external_lsa_originate(route,
+                                                                       ospf6);
+                       }
+               }
+       }
+}
+
+/* Refresh default route */
+static void ospf6_external_lsa_refresh_default(struct ospf6 *ospf6)
+{
+       struct ospf6_route *route;
+       struct ospf6_external_info *info;
+       struct ospf6_lsa *lsa;
+
+       for (route = ospf6_route_head(ospf6->external_table); route;
+            route = ospf6_route_next(route)) {
+               if (is_default_prefix(&route->prefix)) {
+                       info = route->route_option;
+                       lsa = ospf6_lsdb_lookup(htons(OSPF6_LSTYPE_AS_EXTERNAL),
+                                               htonl(info->id),
+                                               ospf6->router_id, ospf6->lsdb);
+
+                       if (lsa) {
+                               if (IS_OSPF6_DEBUG_NSSA)
+                                       zlog_debug(
+                                               "LSA[Type5:0.0.0.0]: Refresh AS-external-LSA %p",
+                                               (void *)lsa);
+                               if (OSPF6_LSA_IS_MAXAGE(lsa))
+                                       ospf6_flood(NULL, lsa);
+                               else
+                                       thread_add_timer(master,
+                                                        ospf6_lsa_refresh, lsa,
+                                                        OSPF_LS_REFRESH_TIME,
+                                                        &lsa->refresh);
+                       } else if (!lsa) {
+                               if (IS_OSPF6_DEBUG_NSSA)
+                                       zlog_debug(
+                                               "LSA[Type5:0.0.0.0]: Originate AS-external-LSA");
+                               ospf6_as_external_lsa_originate(route, ospf6);
+                       }
+               }
+       }
+}
+
+/* If there's redistribution configured, we need to refresh external
+ * LSAs in order to install Type-7 and flood to all NSSA Areas
+ */
+void ospf6_asbr_nssa_redist_task(struct ospf6 *ospf6)
+{
+       int type;
+       struct ospf6_redist *red;
+
+       for (type = 0; type < ZEBRA_ROUTE_MAX; type++) {
+               red = ospf6_redist_lookup(ospf6, type, 0);
+               if (!red)
+                       return;
+
+               ospf6_external_lsa_refresh_type(ospf6, type, red->instance,
+                                               LSA_REFRESH_IF_CHANGED);
+       }
+       ospf6_external_lsa_refresh_default(ospf6);
+}
+
+/* This function performs ABR related processing */
+static int ospf6_abr_task_timer(struct thread *thread)
+{
+       struct ospf6 *ospf6 = THREAD_ARG(thread);
+
+       ospf6->t_abr_task = NULL;
+
+       if (IS_OSPF6_DEBUG_ABR)
+               zlog_debug("Running ABR task on timer");
+
+       ospf6_is_router_abr(ospf6);
+       ospf6_abr_nssa_check_status(ospf6);
+       ospf6_abr_task(ospf6);
+       /* if nssa-abr, then scan Type-7 LSDB */
+       ospf6_abr_nssa_task(ospf6);
+       ospf6_asbr_nssa_redist_task(ospf6);
+
+       return 0;
+}
+
+void ospf6_schedule_abr_task(struct ospf6 *ospf6)
+{
+       if (ospf6->t_abr_task) {
+               if (IS_OSPF6_DEBUG_ABR)
+                       zlog_debug("ABR task already scheduled");
+               return;
+       }
+
+       if (IS_OSPF6_DEBUG_ABR)
+               zlog_debug("Scheduling ABR task");
+
+       thread_add_timer(master, ospf6_abr_task_timer, ospf6,
+                        OSPF6_ABR_TASK_DELAY, &ospf6->t_abr_task);
+}
+
+/* Flush the NSSA LSAs from the area */
+static void ospf6_nssa_flush_area(struct ospf6_area *area)
+{
+       uint16_t type;
+       struct ospf6_lsa *lsa = NULL, *type5 = NULL;
+       struct ospf6 *ospf6 = area->ospf6;
+       const struct route_node *rt = NULL;
+
+       if (IS_OSPF6_DEBUG_NSSA)
+               zlog_debug("%s: area %s", __func__, area->name);
+
+       /* Flush the NSSA LSA */
+       type = htons(OSPF6_LSTYPE_TYPE_7);
+       rt = ospf6_lsdb_head(area->lsdb_self, 0, type, ospf6->router_id, &lsa);
+       while (lsa) {
+               lsa->header->age = htons(OSPF_LSA_MAXAGE);
+               SET_FLAG(lsa->flag, OSPF6_LSA_FLUSH);
+               ospf6_flood(NULL, lsa);
+               /* Flush the translated LSA */
+               if (ospf6_is_router_abr(ospf6)) {
+                       type = htons(OSPF6_LSTYPE_AS_EXTERNAL);
+                       type5 = ospf6_lsdb_lookup(
+                               htons(type), lsa->external_lsa_id,
+                               ospf6->router_id, ospf6->lsdb);
+                       if (type5
+                           && CHECK_FLAG(type5->flag, OSPF6_LSA_LOCAL_XLT)) {
+                               type5->header->age = htons(OSPF_LSA_MAXAGE);
+                               SET_FLAG(type5->flag, OSPF6_LSA_FLUSH);
+                               ospf6_flood(NULL, type5);
+                       }
+               }
+               lsa = ospf6_lsdb_next(rt, lsa);
+       }
+}
+
+static void ospf6_area_nssa_update(struct ospf6_area *area)
+{
+       struct ospf6_route *route;
+
+       if (IS_AREA_NSSA(area)) {
+               if (!ospf6_is_router_abr(area->ospf6))
+                       OSPF6_OPT_CLEAR(area->options, OSPF6_OPT_E);
+               area->ospf6->anyNSSA++;
+               OSPF6_OPT_SET(area->options, OSPF6_OPT_N);
+               area->NSSATranslatorRole = OSPF6_NSSA_ROLE_CANDIDATE;
+       } else if (IS_AREA_ENABLED(area)) {
+               if (IS_OSPF6_DEBUG_ORIGINATE(ROUTER))
+                       zlog_debug("Normal area for if %s", area->name);
+               OSPF6_OPT_CLEAR(area->options, OSPF6_OPT_N);
+               if (ospf6_is_router_abr(area->ospf6))
+                       OSPF6_OPT_SET(area->options, OSPF6_OPT_E);
+               area->ospf6->anyNSSA--;
+               area->NSSATranslatorState = OSPF6_NSSA_TRANSLATE_DISABLED;
+       }
+
+       /* Refresh router LSA */
+       if (IS_AREA_NSSA(area)) {
+               OSPF6_ROUTER_LSA_SCHEDULE(area);
+
+               /* Check if router is ABR */
+               if (ospf6_is_router_abr(area->ospf6)) {
+                       if (IS_OSPF6_DEBUG_NSSA)
+                               zlog_debug("Router is ABR area %s", area->name);
+                       ospf6_schedule_abr_task(area->ospf6);
+               } else {
+                       /* Router is not ABR */
+                       if (IS_OSPF6_DEBUG_NSSA)
+                               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);
+               }
+       } else {
+               /* Disable NSSA */
+               if (IS_OSPF6_DEBUG_NSSA)
+                       zlog_debug("Normal area %s", area->name);
+               ospf6_nssa_flush_area(area);
+               ospf6_area_disable(area);
+               ospf6_area_delete(area);
+       }
+}
+
+int ospf6_area_nssa_set(struct ospf6 *ospf6, struct ospf6_area *area)
+{
+
+       if (!IS_AREA_NSSA(area)) {
+               SET_FLAG(area->flag, OSPF6_AREA_NSSA);
+               if (IS_OSPF6_DEBUG_NSSA)
+                       zlog_debug("area %s nssa set", area->name);
+               ospf6_area_nssa_update(area);
+       }
+
+       return 1;
+}
+
+int ospf6_area_nssa_unset(struct ospf6 *ospf6, struct ospf6_area *area)
+{
+       if (IS_AREA_NSSA(area)) {
+               UNSET_FLAG(area->flag, OSPF6_AREA_NSSA);
+               if (IS_OSPF6_DEBUG_NSSA)
+                       zlog_debug("area %s nssa reset", area->name);
+               ospf6_area_nssa_update(area);
+       }
+
+       return 1;
+}
+
+/* Find the NSSA forwarding address */
+static struct in6_addr *ospf6_get_nssa_fwd_addr(struct ospf6_area *oa)
+{
+       struct listnode *node, *nnode;
+       struct ospf6_interface *oi;
+
+       for (ALL_LIST_ELEMENTS(oa->if_list, node, nnode, oi)) {
+               if (if_is_operative(oi->interface))
+                       if (oi->area && IS_AREA_NSSA(oi->area))
+                               return ospf6_interface_get_global_address(
+                                       oi->interface);
+       }
+       return NULL;
+}
+
+void ospf6_nssa_lsa_originate(struct ospf6_route *route,
+                             struct ospf6_area *area)
+{
+       char buffer[OSPF6_MAX_LSASIZE];
+       struct ospf6_lsa_header *lsa_header;
+       struct ospf6_lsa *lsa;
+       struct ospf6_external_info *info = route->route_option;
+       struct in6_addr *fwd_addr;
+
+       struct ospf6_as_external_lsa *as_external_lsa;
+       char buf[PREFIX2STR_BUFFER];
+       caddr_t p;
+
+       if (IS_OSPF6_DEBUG_ASBR || IS_OSPF6_DEBUG_ORIGINATE(AS_EXTERNAL)) {
+               prefix2str(&route->prefix, buf, sizeof(buf));
+               zlog_debug("Originate AS-External-LSA for %s", buf);
+       }
+
+       /* prepare buffer */
+       memset(buffer, 0, sizeof(buffer));
+       lsa_header = (struct ospf6_lsa_header *)buffer;
+       as_external_lsa = (struct ospf6_as_external_lsa
+                                  *)((caddr_t)lsa_header
+                                     + sizeof(struct ospf6_lsa_header));
+       p = (caddr_t)((caddr_t)as_external_lsa
+                     + sizeof(struct ospf6_as_external_lsa));
+
+       /* Fill AS-External-LSA */
+       /* Metric type */
+       if (route->path.metric_type == OSPF6_PATH_TYPE_EXTERNAL2)
+               SET_FLAG(as_external_lsa->bits_metric, OSPF6_ASBR_BIT_E);
+       else
+               UNSET_FLAG(as_external_lsa->bits_metric, OSPF6_ASBR_BIT_E);
+
+       /* external route tag */
+       if (info->tag)
+               SET_FLAG(as_external_lsa->bits_metric, OSPF6_ASBR_BIT_T);
+       else
+               UNSET_FLAG(as_external_lsa->bits_metric, OSPF6_ASBR_BIT_T);
+
+       /* Set metric */
+       OSPF6_ASBR_METRIC_SET(as_external_lsa, route->path.cost);
+
+       /* prefixlen */
+       as_external_lsa->prefix.prefix_length = route->prefix.prefixlen;
+
+       /* PrefixOptions */
+       as_external_lsa->prefix.prefix_options = route->path.prefix_options;
+
+       /* Set the P bit */
+       as_external_lsa->prefix.prefix_options |= OSPF6_PREFIX_OPTION_P;
+
+       /* don't use refer LS-type */
+       as_external_lsa->prefix.prefix_refer_lstype = htons(0);
+
+       /* set Prefix */
+       memcpy(p, &route->prefix.u.prefix6,
+              OSPF6_PREFIX_SPACE(route->prefix.prefixlen));
+       ospf6_prefix_apply_mask(&as_external_lsa->prefix);
+       p += OSPF6_PREFIX_SPACE(route->prefix.prefixlen);
+
+       /* Forwarding address */
+       fwd_addr = ospf6_get_nssa_fwd_addr(area);
+       if (fwd_addr) {
+               memcpy(p, fwd_addr, sizeof(struct in6_addr));
+               p += sizeof(struct in6_addr);
+               SET_FLAG(as_external_lsa->bits_metric, OSPF6_ASBR_BIT_F);
+       } else
+               UNSET_FLAG(as_external_lsa->bits_metric, OSPF6_ASBR_BIT_F);
+
+       /* External Route Tag */
+       if (CHECK_FLAG(as_external_lsa->bits_metric, OSPF6_ASBR_BIT_T)) {
+               route_tag_t network_order = htonl(info->tag);
+
+               memcpy(p, &network_order, sizeof(network_order));
+               p += sizeof(network_order);
+       }
+
+       /* Fill LSA Header */
+       lsa_header->age = 0;
+       lsa_header->type = htons(OSPF6_LSTYPE_TYPE_7);
+       lsa_header->id = route->path.origin.id;
+       lsa_header->adv_router = area->ospf6->router_id;
+       lsa_header->seqnum =
+               ospf6_new_ls_seqnum(lsa_header->type, lsa_header->id,
+                                   lsa_header->adv_router, area->ospf6->lsdb);
+       lsa_header->length = htons((caddr_t)p - (caddr_t)lsa_header);
+
+       /* LSA checksum */
+       ospf6_lsa_checksum(lsa_header);
+       /* create LSA */
+       lsa = ospf6_lsa_create(lsa_header);
+
+       /* Originate */
+       ospf6_lsa_originate_area(lsa, area);
+}
+
+void ospf6_abr_check_translate_nssa(struct ospf6_area *area,
+                                   struct ospf6_lsa *lsa)
+{
+       struct ospf6_lsa *type5 = NULL;
+       struct ospf6 *ospf6 = area->ospf6;
+
+       if (IS_OSPF6_DEBUG_NSSA)
+               zlog_debug("%s : start", __func__);
+
+       type5 = ospf6_lsdb_lookup(htons(OSPF6_LSTYPE_AS_EXTERNAL),
+                                 lsa->external_lsa_id, ospf6->router_id,
+                                 ospf6->lsdb);
+
+       if (ospf6_is_router_abr(ospf6) && (type5 == NULL)) {
+               if (IS_OSPF6_DEBUG_NSSA)
+                       zlog_debug("%s : Originating type5 LSA", __func__);
+               ospf6_lsa_translated_nssa_new(area, lsa);
+       }
+}
+
+DEFUN(debug_ospf6_nssa, debug_ospf6_nssa_cmd,
+      "debug ospf6 nssa",
+      DEBUG_STR
+      OSPF6_STR
+      "Debug OSPFv3 NSSA function\n")
+{
+       OSPF6_DEBUG_NSSA_ON();
+       return CMD_SUCCESS;
+}
+
+DEFUN(no_debug_ospf6_nssa, no_debug_ospf6_nssa_cmd,
+      "no debug ospf6 nssa",
+      NO_STR
+      DEBUG_STR
+      OSPF6_STR
+      "Debug OSPFv3 NSSA function\n")
+{
+       OSPF6_DEBUG_NSSA_OFF();
+       return CMD_SUCCESS;
+}
+
+void config_write_ospf6_debug_nssa(struct vty *vty)
+{
+       if (IS_OSPF6_DEBUG_NSSA)
+               vty_out(vty, "debug ospf6 nssa\n");
+}
+
+void install_element_ospf6_debug_nssa(void)
+{
+       install_element(ENABLE_NODE, &debug_ospf6_nssa_cmd);
+       install_element(ENABLE_NODE, &no_debug_ospf6_nssa_cmd);
+       install_element(CONFIG_NODE, &debug_ospf6_nssa_cmd);
+       install_element(CONFIG_NODE, &no_debug_ospf6_nssa_cmd);
+}
diff --git a/ospf6d/ospf6_nssa.h b/ospf6d/ospf6_nssa.h
new file mode 100644 (file)
index 0000000..a171d76
--- /dev/null
@@ -0,0 +1,76 @@
+/*
+ * OSPFv3 Not So Stubby Area implementation.
+ *
+ * Copyright (C) 2021 Kaushik Nath
+ * Copyright (C) 2021 Soman K.S
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef OSPF6_NSSA_H
+#define OSPF6_NSSA_H
+
+#define OSPF6_OPTION_NP         0x08
+#define OSPF6_LS_INFINITY       0xffffff
+
+#define OSPF6_OPT_N             (1 << 3) /* Handling Type-7 LSA Capability */
+
+#define OSPF6_DEBUG_NSSA        0x09
+/* Debug option */
+extern unsigned char config_debug_ospf6_nssa;
+
+#define OSPF6_DEBUG_NSSA_ON() (config_debug_ospf6_nssa = 1)
+#define OSPF6_DEBUG_NSSA_OFF() (config_debug_ospf6_nssa = 0)
+#define IS_OSPF6_DEBUG_NSSA config_debug_ospf6_nssa
+
+#define CHECK_LSA_TYPE_1_TO_5_OR_7(type)                                       \
+       ((type == OSPF6_ROUTER_LSA_MIN_SIZE)                                   \
+        || (type == OSPF6_NETWORK_LSA_MIN_SIZE)                               \
+        || (type == OSPF6_LINK_LSA_MIN_SIZE)                                  \
+        || (type == OSPF6_INTRA_PREFIX_LSA_MIN_SIZE)                          \
+        || (type == OSPF6_AS_NSSA_LSA))
+
+#define OSPF6_LSA_APPROVED      0x08
+#define OSPF6_LSA_LOCAL_XLT     0x40
+
+#define OSPF6_ABR_TASK_DELAY    7
+
+int ospf6_area_nssa_no_summary_set(struct ospf6 *ospf6, struct in_addr area_id);
+int ospf6_area_nssa_unset(struct ospf6 *ospf6, struct ospf6_area *area);
+int ospf6_area_nssa_set(struct ospf6 *ospf6, struct ospf6_area *area);
+
+extern void ospf6_nssa_lsa_flush(struct ospf6 *ospf6, struct prefix_ipv6 *p);
+extern struct ospf6_lsa *ospf6_translated_nssa_refresh(struct ospf6_area *,
+                                                      struct ospf6_lsa *,
+                                                      struct ospf6_lsa *);
+extern struct ospf6_lsa *ospf6_translated_nssa_originate(struct ospf6_area *,
+                                                        struct ospf6_lsa *);
+
+extern void ospf6_asbr_nssa_redist_task(struct ospf6 *ospf6);
+
+extern void ospf6_schedule_abr_task(struct ospf6 *ospf6);
+void ospf6_asbr_prefix_readvertise(struct ospf6 *ospf6);
+extern void ospf6_nssa_lsa_originate(struct ospf6_route *route,
+                                    struct ospf6_area *area);
+extern void install_element_ospf6_debug_nssa(void);
+int ospf6_redistribute_check(struct ospf6 *ospf6, struct ospf6_route *route,
+                            int type);
+extern int ospf6_abr_translate_nssa(struct ospf6_area *area,
+                                   struct ospf6_lsa *lsa);
+extern void ospf6_abr_check_translate_nssa(struct ospf6_area *area,
+                                          struct ospf6_lsa *lsa);
+extern void ospf6_abr_nssa_check_status(struct ospf6 *ospf6);
+extern void config_write_ospf6_debug_nssa(struct vty *vty);
+#endif /* OSPF6_NSSA_H */
index da6b270e0174581ba3b2ffed49f13812f0cd3b72..b98dc38b728e26fca094bce5cd866b46cfa7e98a 100644 (file)
@@ -35,6 +35,8 @@
 #define OSPF6_ROUTER_BIT_V     (1 << 2)
 #define OSPF6_ROUTER_BIT_E     (1 << 1)
 #define OSPF6_ROUTER_BIT_B     (1 << 0)
+#define OSPF6_ROUTER_BIT_NT    (1 << 4)
+
 
 /* OSPF options */
 /* present in HELLO, DD, LSA */
index 7652d71c59d52ed52e7050dca9bc14a674cf254f..1d32844fecf6f63cb5c0abbaa4bb695b3126cbf0 100644 (file)
 #include "ospf6_area.h"
 #include "ospf6_proto.h"
 #include "ospf6_abr.h"
+#include "ospf6_asbr.h"
 #include "ospf6_spf.h"
 #include "ospf6_intra.h"
 #include "ospf6_interface.h"
 #include "ospf6d.h"
 #include "ospf6_abr.h"
+#include "ospf6_nssa.h"
 
 DEFINE_MTYPE_STATIC(OSPF6D, OSPF6_VERTEX, "OSPF6 vertex");
 
@@ -640,6 +642,9 @@ static int ospf6_spf_calculation_thread(struct thread *t)
                areas_processed++;
        }
 
+       /* External LSA calculation */
+       ospf6_ase_calculate_timer_add(ospf6);
+
        if (ospf6_is_router_abr(ospf6))
                ospf6_abr_defaults_to_stub(ospf6);
 
@@ -1105,3 +1110,183 @@ void ospf6_remove_temp_router_lsa(struct ospf6_area *area)
                ospf6_lsdb_remove(lsa, area->temp_router_lsa_lsdb);
        }
 }
+
+int ospf6_ase_calculate_route(struct ospf6 *ospf6, struct ospf6_lsa *lsa,
+                             struct ospf6_area *area)
+{
+       struct ospf6_route *route, *old;
+       struct ospf6_as_external_lsa *external;
+       struct prefix prefix;
+       void (*hook_add)(struct ospf6_route *) = NULL;
+       void (*hook_remove)(struct ospf6_route *) = NULL;
+
+       assert(lsa);
+
+       if (IS_OSPF6_DEBUG_SPF(PROCESS))
+               zlog_debug("%s :  start", __func__);
+
+       if (ntohs(lsa->header->type) == OSPF6_LSTYPE_TYPE_7)
+               if (IS_OSPF6_DEBUG_SPF(PROCESS))
+                       zlog_debug("%s: Processing Type-7", __func__);
+
+       /* Stay away from any Local Translated Type-7 LSAs */
+       if (CHECK_FLAG(lsa->flag, OSPF6_LSA_LOCAL_XLT)) {
+               if (IS_OSPF6_DEBUG_SPF(PROCESS))
+                       zlog_debug("%s: Rejecting Local translated LSA",
+                                  __func__);
+               return 0;
+       }
+
+       external = (struct ospf6_as_external_lsa *)OSPF6_LSA_HEADER_END(
+               lsa->header);
+       prefix.family = AF_INET6;
+       prefix.prefixlen = external->prefix.prefix_length;
+       ospf6_prefix_in6_addr(&prefix.u.prefix6, external, &external->prefix);
+
+       if (ntohs(lsa->header->type) == OSPF6_LSTYPE_AS_EXTERNAL) {
+               hook_add = ospf6->route_table->hook_add;
+               hook_remove = ospf6->route_table->hook_remove;
+               ospf6->route_table->hook_add = NULL;
+               ospf6->route_table->hook_remove = NULL;
+
+               old = ospf6_route_lookup(&prefix, ospf6->route_table);
+               if (old) {
+                       if (IS_OSPF6_DEBUG_SPF(PROCESS))
+                               zlog_debug("%s : remove external route %pFX",
+                                          __func__, &prefix);
+                       old->flag = OSPF6_ROUTE_REMOVE;
+               }
+
+               if (!OSPF6_LSA_IS_MAXAGE(lsa))
+                       ospf6_asbr_lsa_add(lsa);
+
+               ospf6->route_table->hook_add = hook_add;
+               ospf6->route_table->hook_remove = hook_remove;
+
+               route = ospf6_route_lookup(&prefix, ospf6->route_table);
+               if (route == NULL) {
+                       if (IS_OSPF6_DEBUG_SPF(PROCESS))
+                               zlog_debug("%s : no external route %pFX",
+                                          __func__, &prefix);
+                       return 0;
+               }
+
+               if (CHECK_FLAG(route->flag, OSPF6_ROUTE_REMOVE)
+                   && (CHECK_FLAG(route->flag, OSPF6_ROUTE_ADD)
+                       || (old == route))) {
+                       UNSET_FLAG(route->flag, OSPF6_ROUTE_REMOVE);
+                       UNSET_FLAG(route->flag, OSPF6_ROUTE_ADD);
+               }
+
+               if (CHECK_FLAG(route->flag, OSPF6_ROUTE_REMOVE))
+                       ospf6_route_remove(route, ospf6->route_table);
+               else if (CHECK_FLAG(route->flag, OSPF6_ROUTE_ADD)
+                        || CHECK_FLAG(route->flag, OSPF6_ROUTE_CHANGE)) {
+                       if (hook_add) {
+                               if (IS_OSPF6_DEBUG_SPF(PROCESS))
+                                       zlog_debug(
+                                               "%s: add external route %pFX",
+                                               __func__, &prefix);
+                               (*hook_add)(route);
+                       }
+                       route->flag = 0;
+               }
+       } else if (ntohs(lsa->header->type) == OSPF6_LSTYPE_TYPE_7) {
+               hook_add = area->route_table->hook_add;
+               hook_remove = area->route_table->hook_remove;
+               area->route_table->hook_add = NULL;
+               area->route_table->hook_remove = NULL;
+
+               old = ospf6_route_lookup(&prefix, area->route_table);
+               if (old) {
+                       if (IS_OSPF6_DEBUG_SPF(PROCESS))
+                               zlog_debug(
+                                       "%s: set remove flag nssa route %pFX, area %s",
+                                       __func__, &prefix, area->name);
+                       old->flag = OSPF6_ROUTE_REMOVE;
+               }
+
+               if (!OSPF6_LSA_IS_MAXAGE(lsa))
+                       ospf6_asbr_lsa_add(lsa);
+
+               area->route_table->hook_add = hook_add;
+               area->route_table->hook_remove = hook_remove;
+
+               route = ospf6_route_lookup(&prefix, area->route_table);
+               if (route == NULL) {
+                       if (IS_OSPF6_DEBUG_SPF(PROCESS))
+                               zlog_debug("%s : no route %pFX, area %s",
+                                          __func__, &prefix, area->name);
+                       return 0;
+               }
+
+               if (CHECK_FLAG(route->flag, OSPF6_ROUTE_REMOVE)
+                   && (CHECK_FLAG(route->flag, OSPF6_ROUTE_ADD)
+                       || (old == route))) {
+                       UNSET_FLAG(route->flag, OSPF6_ROUTE_REMOVE);
+                       UNSET_FLAG(route->flag, OSPF6_ROUTE_ADD);
+               }
+
+               if (CHECK_FLAG(route->flag, OSPF6_ROUTE_REMOVE)) {
+                       if (IS_OSPF6_DEBUG_SPF(PROCESS))
+                               zlog_debug("%s : remove route %pFX, area %s",
+                                          __func__, &prefix, area->name);
+                       ospf6_route_remove(route, area->route_table);
+               } else if (CHECK_FLAG(route->flag, OSPF6_ROUTE_ADD)
+                          || CHECK_FLAG(route->flag, OSPF6_ROUTE_CHANGE)) {
+                       if (hook_add) {
+                               if (IS_OSPF6_DEBUG_SPF(PROCESS))
+                                       zlog_debug(
+                                               "%s: add nssa route %pFX, area %s",
+                                               __func__, &prefix, area->name);
+                               (*hook_add)(route);
+                       }
+                       ospf6_abr_check_translate_nssa(area, lsa);
+                       route->flag = 0;
+               }
+       }
+       return 0;
+}
+
+static int ospf6_ase_calculate_timer(struct thread *t)
+{
+       struct ospf6 *ospf6;
+       struct ospf6_lsa *lsa;
+       struct listnode *node, *nnode;
+       struct ospf6_area *area;
+       uint16_t type;
+
+       ospf6 = THREAD_ARG(t);
+       ospf6->t_ase_calc = NULL;
+
+       /* Calculate external route for each AS-external-LSA */
+       type = htons(OSPF6_LSTYPE_AS_EXTERNAL);
+       for (ALL_LSDB_TYPED(ospf6->lsdb, type, lsa))
+               ospf6_ase_calculate_route(ospf6, lsa, NULL);
+
+       /*  This version simple adds to the table all NSSA areas  */
+       if (ospf6->anyNSSA) {
+               for (ALL_LIST_ELEMENTS(ospf6->area_list, node, nnode, area)) {
+                       if (IS_OSPF6_DEBUG_SPF(PROCESS))
+                               zlog_debug("%s : looking at area %s", __func__,
+                                          area->name);
+
+                       if (IS_OSPF6_DEBUG_SPF(PROCESS)) {
+                               type = htons(OSPF6_LSTYPE_TYPE_7);
+                               for (ALL_LSDB_TYPED(area->lsdb, type, lsa))
+                                       ospf6_ase_calculate_route(ospf6, lsa,
+                                                                 area);
+                       }
+               }
+       }
+       return 0;
+}
+
+void ospf6_ase_calculate_timer_add(struct ospf6 *ospf6)
+{
+       if (ospf6 == NULL)
+               return;
+
+       thread_add_timer(master, ospf6_ase_calculate_timer, ospf6,
+                        OSPF6_ASE_CALC_INTERVAL, &ospf6->t_ase_calc);
+}
index 4660bfd05db9f391eae4b27dc2a7897a1da2f650..1ccad57b6209962176800bc3e03b637ec26ef23d 100644 (file)
@@ -35,7 +35,9 @@ extern unsigned char conf_debug_ospf6_spf;
 #define IS_OSPF6_DEBUG_SPF(level)                                              \
        (conf_debug_ospf6_spf & OSPF6_DEBUG_SPF_##level)
 
-PREDECL_SKIPLIST_NONUNIQ(vertex_pqueue);
+#define OSPF6_ASE_CALC_INTERVAL 1
+
+PREDECL_SKIPLIST_NONUNIQ(vertex_pqueue)
 /* Transit Vertex */
 struct ospf6_vertex {
        /* type of this vertex */
@@ -161,5 +163,7 @@ extern struct ospf6_lsa *ospf6_create_single_router_lsa(struct ospf6_area *area,
                                                        struct ospf6_lsdb *lsdb,
                                                        uint32_t adv_router);
 extern void ospf6_remove_temp_router_lsa(struct ospf6_area *area);
-
+extern void ospf6_ase_calculate_timer_add(struct ospf6 *ospf6);
+extern int ospf6_ase_calculate_route(struct ospf6 *ospf6, struct ospf6_lsa *lsa,
+                                    struct ospf6_area *area);
 #endif /* OSPF6_SPF_H */
index 42405ca35ea48fdeb6df88185bae163d87a7f4fa..33b5dd196072d177d7fc1611b4b3cecd04368b33 100644 (file)
@@ -52,6 +52,7 @@
 #include "ospf6_spf.h"
 #include "ospf6d.h"
 #include "lib/json.h"
+#include "ospf6_nssa.h"
 
 DEFINE_MTYPE_STATIC(OSPF6D, OSPF6_TOP, "OSPF6 top");
 
@@ -259,7 +260,15 @@ static void ospf6_top_lsdb_hook_remove(struct ospf6_lsa *lsa)
 
 static void ospf6_top_route_hook_add(struct ospf6_route *route)
 {
-       struct ospf6 *ospf6 = route->table->scope;
+       struct ospf6 *ospf6 = NULL;
+       struct ospf6_area *oa = NULL;
+
+       if (route->table->scope_type == OSPF6_SCOPE_TYPE_GLOBAL)
+               ospf6 = route->table->scope;
+       else if (route->table->scope_type == OSPF6_SCOPE_TYPE_AREA) {
+               oa = (struct ospf6_area *)route->table->scope;
+               ospf6 = oa->ospf6;
+       }
 
        ospf6_abr_originate_summary(route, ospf6);
        ospf6_zebra_route_update_add(route, ospf6);
@@ -267,7 +276,15 @@ static void ospf6_top_route_hook_add(struct ospf6_route *route)
 
 static void ospf6_top_route_hook_remove(struct ospf6_route *route)
 {
-       struct ospf6 *ospf6 = route->table->scope;
+       struct ospf6 *ospf6 = NULL;
+       struct ospf6_area *oa = NULL;
+
+       if (route->table->scope_type == OSPF6_SCOPE_TYPE_GLOBAL)
+               ospf6 = route->table->scope;
+       else if (route->table->scope_type == OSPF6_SCOPE_TYPE_AREA) {
+               oa = (struct ospf6_area *)route->table->scope;
+               ospf6 = oa->ospf6;
+       }
 
        route->flag |= OSPF6_ROUTE_REMOVE;
        ospf6_abr_originate_summary(route, ospf6);
@@ -917,8 +934,10 @@ DEFUN (ospf6_interface_area,
        ospf6_interface_enable(oi);
 
        /* If the router is ABR, originate summary routes */
-       if (ospf6_is_router_abr(ospf6))
+       if (ospf6_is_router_abr(ospf6)) {
                ospf6_abr_enable_area(oa);
+               ospf6_schedule_abr_task(oa->ospf6);
+       }
 
        return CMD_SUCCESS;
 }
index 238d6a40ce230c55cdb522703ca70a1094278500..e4dfebe1de186dd2c98bf1a27fe95139068b049a 100644 (file)
@@ -95,6 +95,8 @@ struct ospf6 {
        struct list *redist[ZEBRA_ROUTE_MAX + 1];
 
        uint8_t flag;
+#define OSPF6_FLAG_ABR          0x04
+#define OSPF6_FLAG_ASBR         0x08
 
        int redistribute; /* Num of redistributed protocols. */
 
@@ -145,14 +147,17 @@ struct ospf6 {
         * to support ECMP.
         */
        uint16_t max_multipath;
+       /* Count of NSSA areas */
+       uint8_t anyNSSA;
+       struct thread *t_abr_task; /* ABR task timer. */
 
+       uint32_t redist_count;
        QOBJ_FIELDS;
 };
 DECLARE_QOBJ_TYPE(ospf6);
 
 #define OSPF6_DISABLED    0x01
 #define OSPF6_STUB_ROUTER 0x02
-#define OSPF6_FLAG_ASBR   0x04
 #define OSPF6_MAX_IF_ADDRS 100
 #define OSPF6_MAX_IF_ADDRS_JUMBO 200
 #define OSPF6_DEFAULT_MTU 1500
index da8c695f6502e0774b33f5cb3f4db24c99a1ef38..65f0aa664e786dd215fa35c365f2afd3edae052d 100644 (file)
@@ -46,6 +46,7 @@
 #include "ospf6d.h"
 #include "ospf6_bfd.h"
 #include "lib/json.h"
+#include "ospf6_nssa.h"
 
 DEFINE_MGROUP(OSPF6D, "ospf6d");
 
@@ -94,6 +95,7 @@ static int config_write_ospf6_debug(struct vty *vty)
        config_write_ospf6_debug_asbr(vty);
        config_write_ospf6_debug_abr(vty);
        config_write_ospf6_debug_flood(vty);
+       config_write_ospf6_debug_nssa(vty);
 
        return 0;
 }
@@ -153,6 +155,8 @@ static uint16_t parse_type_spec(int idx_lsa, int argc, struct cmd_token **argv)
                        type = htons(OSPF6_LSTYPE_INTER_PREFIX);
                else if (strmatch(argv[idx_lsa]->text, "link"))
                        type = htons(OSPF6_LSTYPE_LINK);
+               else if (strmatch(argv[idx_lsa]->text, "type-7"))
+                       type = htons(OSPF6_LSTYPE_TYPE_7);
        }
 
        return type;
@@ -1419,6 +1423,7 @@ void ospf6_init(struct thread_master *master)
        install_element_ospf6_debug_asbr();
        install_element_ospf6_debug_abr();
        install_element_ospf6_debug_flood();
+       install_element_ospf6_debug_nssa();
 
        install_element_ospf6_clear_interface();
 
index 00388afd38fdafedced8ebb9489e568be688a42b..2e1891be7189daa8955c3d588f746afeb160882e 100644 (file)
@@ -6,6 +6,7 @@ if OSPF6D
 noinst_LIBRARIES += ospf6d/libospf6.a
 sbin_PROGRAMS += ospf6d/ospf6d
 vtysh_scan += \
+       ospf6d/ospf6_nssa.c \
        ospf6d/ospf6_abr.c \
        ospf6d/ospf6_asbr.c \
        ospf6d/ospf6_area.c \
@@ -30,6 +31,7 @@ man8 += $(MANBUILD)/frr-ospf6d.8
 endif
 
 ospf6d_libospf6_a_SOURCES = \
+       ospf6d/ospf6_nssa.c \
        ospf6d/ospf6_abr.c \
        ospf6d/ospf6_area.c \
        ospf6d/ospf6_asbr.c \
@@ -53,6 +55,7 @@ ospf6d_libospf6_a_SOURCES = \
        # end
 
 noinst_HEADERS += \
+       ospf6d/ospf6_nssa.h \
        ospf6d/ospf6_abr.h \
        ospf6d/ospf6_area.h \
        ospf6d/ospf6_asbr.h \