]> git.proxmox.com Git - mirror_frr.git/blobdiff - ospfd/ospf_ri.c
lib: enforce vrf_name_to_id by returning default_vrf when name is null
[mirror_frr.git] / ospfd / ospf_ri.c
index bef16761f2831346f0b8700222924330aac2ac4a..72f6dbe08e220c95e43bf38e1f3cb7f191a140af 100644 (file)
 #include "ospfd/ospf_ri.h"
 #include "ospfd/ospf_errors.h"
 
-/* Store Router Information PCE TLV and SubTLV in network byte order. */
-struct ospf_pce_info {
-       bool enabled;
-       struct ri_tlv_pce pce_header;
-       struct ri_pce_subtlv_address pce_address;
-       struct ri_pce_subtlv_path_scope pce_scope;
-       struct list *pce_domain;
-       struct list *pce_neighbor;
-       struct ri_pce_subtlv_cap_flag pce_cap_flag;
-};
-
-/*
- * Store Router Information Segment Routing TLV and SubTLV
- * in network byte order
- */
-struct ospf_ri_sr_info {
-       bool enabled;
-       /* Algorithms supported by the node */
-       struct ri_sr_tlv_sr_algorithm algo;
-       /*
-        * Segment Routing Global Block i.e. label range
-        * Only one range supported in this code
-        */
-       struct ri_sr_tlv_sid_label_range range;
-       /* Maximum SID Depth supported by the node */
-       struct ri_sr_tlv_node_msd msd;
-};
-
-/* Following structure are internal use only. */
-struct ospf_router_info {
-       bool enabled;
-
-       uint8_t registered;
-       uint8_t scope;
-
-/* Flags to manage this router information. */
-#define RIFLG_LSA_ENGAGED              0x1
-#define RIFLG_LSA_FORCED_REFRESH       0x2
-       uint32_t flags;
-
-       /* area pointer if flooding is Type 10 Null if flooding is AS scope */
-       struct ospf_area *area;
-       struct in_addr area_id;
-
-       /* Store Router Information Capabilities LSA */
-       struct ri_tlv_router_cap router_cap;
-
-       /* Store PCE capability LSA */
-       struct ospf_pce_info pce_info;
-
-       /* Store SR capability LSA */
-       struct ospf_ri_sr_info sr_info;
-};
-
 /*
  * Global variable to manage Opaque-LSA/Router Information on this node.
  * Note that all parameter values are stored in network byte order.
@@ -126,28 +72,29 @@ static struct ospf_router_info OspfRI;
 
 static void ospf_router_info_ism_change(struct ospf_interface *oi,
                                        int old_status);
-static void ospf_router_info_nsm_change(struct ospf_neighbor *nbr,
-                                       int old_status);
 static void ospf_router_info_config_write_router(struct vty *vty);
 static void ospf_router_info_show_info(struct vty *vty, struct ospf_lsa *lsa);
 static int ospf_router_info_lsa_originate(void *arg);
 static struct ospf_lsa *ospf_router_info_lsa_refresh(struct ospf_lsa *lsa);
-static void ospf_router_info_lsa_schedule(enum lsa_opcode opcode);
+static void ospf_router_info_lsa_schedule(struct ospf_ri_area_info *ai,
+                                         enum lsa_opcode opcode);
 static void ospf_router_info_register_vty(void);
 static int ospf_router_info_lsa_update(struct ospf_lsa *lsa);
+static void del_area_info(void *val);
 static void del_pce_info(void *val);
 
 int ospf_router_info_init(void)
 {
 
-       zlog_info("RI -> Initialize Router Information");
+       zlog_info("RI (%s): Initialize Router Information", __func__);
 
        memset(&OspfRI, 0, sizeof(struct ospf_router_info));
        OspfRI.enabled = false;
        OspfRI.registered = 0;
        OspfRI.scope = OSPF_OPAQUE_AS_LSA;
-       OspfRI.area_id.s_addr = 0;
-       OspfRI.flags = 0;
+       OspfRI.as_flags = RIFLG_LSA_INACTIVE;
+       OspfRI.area_info = list_new();
+       OspfRI.area_info->del = del_area_info;
 
        /* Initialize pce domain and neighbor list */
        OspfRI.pce_info.enabled = false;
@@ -171,13 +118,15 @@ static int ospf_router_info_register(uint8_t scope)
        if (OspfRI.registered)
                return rc;
 
-       zlog_info("RI -> Register Router Information with scope %s(%d)",
+       zlog_info("RI (%s): Register Router Information with scope %s(%d)",
+                 __func__,
                  scope == OSPF_OPAQUE_AREA_LSA ? "Area" : "AS", scope);
        rc = ospf_register_opaque_functab(
                scope, OPAQUE_TYPE_ROUTER_INFORMATION_LSA,
                NULL, /* new interface */
                NULL, /* del interface */
-               ospf_router_info_ism_change, ospf_router_info_nsm_change,
+               ospf_router_info_ism_change,
+               NULL, /* NSM change */
                ospf_router_info_config_write_router,
                NULL, /* Config. write interface */
                NULL, /* Config. write debug */
@@ -188,7 +137,7 @@ static int ospf_router_info_register(uint8_t scope)
        if (rc != 0) {
                flog_warn(
                        EC_OSPF_OPAQUE_REGISTRATION,
-                       "ospf_router_info_init: Failed to register functions");
+                       "RI (%s): Failed to register functions", __func__);
                return rc;
        }
 
@@ -235,10 +184,14 @@ void ospf_router_info_finish(void)
        OspfRI.enabled = false;
 }
 
+static void del_area_info(void *val)
+{
+       XFREE(MTYPE_OSPF_ROUTER_INFO, val);
+}
+
 static void del_pce_info(void *val)
 {
        XFREE(MTYPE_OSPF_PCE_PARAMS, val);
-       return;
 }
 
 /* Catch RI LSA flooding Scope for ospf_ext.[h,c] code */
@@ -248,14 +201,26 @@ struct scope_info ospf_router_info_get_flooding_scope(void)
 
        if (OspfRI.scope == OSPF_OPAQUE_AS_LSA) {
                flooding_scope.scope = OSPF_OPAQUE_AS_LSA;
-               flooding_scope.area_id.s_addr = 0;
+               flooding_scope.areas = NULL;
                return flooding_scope;
        }
        flooding_scope.scope = OSPF_OPAQUE_AREA_LSA;
-       flooding_scope.area_id.s_addr = OspfRI.area_id.s_addr;
+       flooding_scope.areas = OspfRI.area_info;
        return flooding_scope;
 }
 
+static struct ospf_ri_area_info *lookup_by_area(struct ospf_area *area)
+{
+       struct listnode *node, *nnode;
+       struct ospf_ri_area_info *ai;
+
+       for (ALL_LIST_ELEMENTS(OspfRI.area_info, node, nnode, ai))
+               if (ai->area == area)
+                       return ai;
+
+       return NULL;
+}
+
 /*------------------------------------------------------------------------*
  * Followings are control functions for ROUTER INFORMATION parameters
  *management.
@@ -525,6 +490,9 @@ static void initialize_params(struct ospf_router_info *ori)
 {
        uint32_t cap = 0;
        struct ospf *top;
+       struct listnode *node, *nnode;
+       struct ospf_area *area;
+       struct ospf_ri_area_info *new;
 
        /*
         * Initialize default Router Information Capabilities.
@@ -536,14 +504,22 @@ static void initialize_params(struct ospf_router_info *ori)
        /* If Area address is not null and exist, retrieve corresponding
         * structure */
        top = ospf_lookup_by_vrf_id(VRF_DEFAULT);
-       zlog_info("RI-> Initialize Router Info for %s scope within area %s",
-                 OspfRI.scope == OSPF_OPAQUE_AREA_LSA ? "Area" : "AS",
-                 inet_ntoa(OspfRI.area_id));
+       zlog_info("RI (%s): Initialize Router Info for %s scope", __func__,
+                 OspfRI.scope == OSPF_OPAQUE_AREA_LSA ? "Area" : "AS");
 
-       /* Try to get the Area context at this step. Do it latter if not
-        * available */
-       if ((OspfRI.scope == OSPF_OPAQUE_AREA_LSA) && (OspfRI.area == NULL))
-               OspfRI.area = ospf_area_lookup_by_area_id(top, OspfRI.area_id);
+       /* Try to get available Area's context from ospf at this step.
+        * Do it latter if not available */
+       if (OspfRI.scope == OSPF_OPAQUE_AREA_LSA) {
+               for (ALL_LIST_ELEMENTS(top->areas, node, nnode, area)) {
+                       zlog_debug("RI (%s): Add area %s to Router Information",
+                               __func__, inet_ntoa(area->area_id));
+                       new = XCALLOC(MTYPE_OSPF_ROUTER_INFO,
+                               sizeof(struct ospf_ri_area_info));
+                       new->area = area;
+                       new->flags = RIFLG_LSA_INACTIVE;
+                       listnode_add(OspfRI.area_info, new);
+               }
+       }
 
        /*
         * Initialize default PCE Information values
@@ -597,16 +573,31 @@ static int is_mandated_params_set(struct ospf_router_info ori)
  */
 void ospf_router_info_update_sr(bool enable, struct sr_srgb srgb, uint8_t msd)
 {
+       struct listnode *node, *nnode;
+       struct ospf_ri_area_info *ai;
+
+       /* First, check if Router Information is registered or not */
+       if (!OspfRI.registered)
+               ospf_router_info_register(OSPF_OPAQUE_AREA_LSA);
+
+       /* Verify that scope is AREA */
+       if (OspfRI.scope != OSPF_OPAQUE_AREA_LSA) {
+               zlog_err(
+                       "RI (%s): Router Info is %s flooding: Change scope to Area flooding for Segment Routing",
+                       __func__,
+                       OspfRI.scope == OSPF_OPAQUE_AREA_LSA ? "Area" : "AS");
+               return;
+       }
 
-       /* First activate and initialize Router Information is necessary */
+       /* Then, activate and initialize Router Information if necessary */
        if (!OspfRI.enabled) {
                OspfRI.enabled = true;
                initialize_params(&OspfRI);
        }
 
        if (IS_DEBUG_OSPF_SR)
-               zlog_debug("RI-> %s Routing Information for Segment Routing",
-                          enable ? "Enable" : "Disable");
+               zlog_debug("RI (%s): %s Routing Information for Segment Routing",
+                          __func__, enable ? "Enable" : "Disable");
 
        /* Unset or Set SR parameters */
        if (!enable) {
@@ -626,10 +617,14 @@ void ospf_router_info_update_sr(bool enable, struct sr_srgb srgb, uint8_t msd)
        }
 
        /* Refresh if already engaged or originate RI LSA */
-       if (CHECK_FLAG(OspfRI.flags, RIFLG_LSA_ENGAGED))
-               ospf_router_info_lsa_schedule(REFRESH_THIS_LSA);
-       else
-               ospf_router_info_lsa_schedule(REORIGINATE_THIS_LSA);
+       for (ALL_LIST_ELEMENTS(OspfRI.area_info, node, nnode, ai)) {
+               if (CHECK_FLAG(ai->flags, RIFLG_LSA_ENGAGED))
+                       ospf_router_info_lsa_schedule(ai, REFRESH_THIS_LSA);
+               else
+                       ospf_router_info_lsa_schedule(ai,
+                               REORIGINATE_THIS_LSA);
+
+       }
 }
 
 /*------------------------------------------------------------------------*
@@ -638,14 +633,22 @@ void ospf_router_info_update_sr(bool enable, struct sr_srgb srgb, uint8_t msd)
 static void ospf_router_info_ism_change(struct ospf_interface *oi,
                                        int old_state)
 {
-       /* So far, nothing to do here. */
-       return;
-}
 
-static void ospf_router_info_nsm_change(struct ospf_neighbor *nbr,
-                                       int old_state)
-{
-       /* So far, nothing to do here. */
+       struct ospf_ri_area_info *ai;
+
+       /* Collect area information */
+       ai = lookup_by_area(oi->area);
+
+       /* Check if area is not yet registered */
+       if (ai != NULL)
+               return;
+
+       /* Add this new area to the list */
+       ai = XCALLOC(MTYPE_OSPF_ROUTER_INFO, sizeof(struct ospf_ri_area_info));
+       ai->area = oi->area;
+       ai->flags = RIFLG_LSA_INACTIVE;
+       listnode_add(OspfRI.area_info, ai);
+
        return;
 }
 
@@ -723,7 +726,7 @@ static void ospf_router_info_lsa_body_set(struct stream *s)
 }
 
 /* Create new opaque-LSA. */
-static struct ospf_lsa *ospf_router_info_lsa_new()
+static struct ospf_lsa *ospf_router_info_lsa_new(struct ospf_area *area)
 {
        struct ospf *top;
        struct stream *s;
@@ -768,8 +771,7 @@ static struct ospf_lsa *ospf_router_info_lsa_new()
        /* Now, create an OSPF LSA instance. */
        new = ospf_lsa_new_and_data(length);
 
-       new->area = OspfRI.area; /* Area must be null if the Opaque type is AS
-                                   scope, fulfill otherwise */
+       new->area = area;
 
        if (new->area && new->area->ospf)
                new->vrf_id = new->area->ospf->vrf_id;
@@ -783,36 +785,31 @@ static struct ospf_lsa *ospf_router_info_lsa_new()
        return new;
 }
 
-static int ospf_router_info_lsa_originate1(void *arg)
+static int ospf_router_info_lsa_originate_as(void *arg)
 {
        struct ospf_lsa *new;
        struct ospf *top;
-       struct ospf_area *area;
        int rc = -1;
        vrf_id_t vrf_id = VRF_DEFAULT;
 
-       /* First check if the area is known if flooding scope is Area */
+       /* Sanity Check */
        if (OspfRI.scope == OSPF_OPAQUE_AREA_LSA) {
-               area = (struct ospf_area *)arg;
-               if (area->area_id.s_addr != OspfRI.area_id.s_addr) {
-                       zlog_debug(
-                               "RI -> This is not the Router Information Area. Stop processing");
-                       return rc;
-               }
-               OspfRI.area = area;
-               if (area->ospf)
-                       vrf_id = area->ospf->vrf_id;
+               flog_warn(
+                       EC_OSPF_LSA_INSTALL_FAILURE,
+                       "RI (%s): wrong flooding scope AREA instead of AS ?",
+                       __func__);
+               return rc;
        }
 
        /* Create new Opaque-LSA/ROUTER INFORMATION instance. */
-       new = ospf_router_info_lsa_new();
-       new->vrf_id = vrf_id;
+       new = ospf_router_info_lsa_new(NULL);
+       new->vrf_id = VRF_DEFAULT;
+       top = (struct ospf *)arg;
 
-       /* Get ospf info */
-       top = ospf_lookup_by_vrf_id(vrf_id);
+       /* Check ospf info */
        if (top == NULL) {
-               zlog_debug("%s: ospf instance not found for vrf id %u",
-                          __PRETTY_FUNCTION__, vrf_id);
+               zlog_debug("RI (%s): ospf instance not found for vrf id %u",
+                          __func__, vrf_id);
                ospf_lsa_unlock(&new);
                return rc;
        }
@@ -821,22 +818,86 @@ static int ospf_router_info_lsa_originate1(void *arg)
        if (ospf_lsa_install(top, NULL /*oi */, new) == NULL) {
                flog_warn(
                        EC_OSPF_LSA_INSTALL_FAILURE,
-                       "ospf_router_info_lsa_originate1: ospf_lsa_install() ?");
+                       "RI (%s): ospf_lsa_install() ?", __func__);
+               ospf_lsa_unlock(&new);
+               return rc;
+       }
+
+       /* Update new LSA origination count. */
+       top->lsa_originate_count++;
+
+       /* Flood new LSA through AREA or AS. */
+       SET_FLAG(OspfRI.as_flags, RIFLG_LSA_ENGAGED);
+       ospf_flood_through_as(top, NULL /*nbr */, new);
+
+       if (IS_DEBUG_OSPF(lsa, LSA_GENERATE)) {
+               zlog_debug(
+                       "LSA[Type%d:%s]: Originate Opaque-LSA/ROUTER INFORMATION",
+                       new->data->type, inet_ntoa(new->data->id));
+               ospf_lsa_header_dump(new->data);
+       }
+
+       rc = 0;
+       return rc;
+}
+
+static int ospf_router_info_lsa_originate_area(void *arg)
+{
+       struct ospf_lsa *new;
+       struct ospf *top;
+       struct ospf_ri_area_info *ai = NULL;
+       int rc = -1;
+       vrf_id_t vrf_id = VRF_DEFAULT;
+
+       /* Sanity Check */
+       if (OspfRI.scope == OSPF_OPAQUE_AS_LSA) {
+               flog_warn(
+                       EC_OSPF_LSA_INSTALL_FAILURE,
+                       "RI (%s): wrong flooding scope AS instead of AREA ?",
+                       __func__);
+               return rc;
+       }
+
+       /* Create new Opaque-LSA/ROUTER INFORMATION instance. */
+       ai = lookup_by_area((struct ospf_area *)arg);
+       if (ai == NULL) {
+               zlog_debug(
+                       "RI (%s): There is no context for this Router Information. Stop processing",
+                       __func__);
+               return rc;
+       }
+       if (ai->area->ospf) {
+               vrf_id = ai->area->ospf->vrf_id;
+               top = ai->area->ospf;
+       } else {
+               top = ospf_lookup_by_vrf_id(vrf_id);
+       }
+       new = ospf_router_info_lsa_new(ai->area);
+       new->vrf_id = vrf_id;
+
+       /* Check ospf info */
+       if (top == NULL) {
+               zlog_debug("RI (%s): ospf instance not found for vrf id %u",
+                          __func__, vrf_id);
                ospf_lsa_unlock(&new);
                return rc;
        }
 
-       /* Now this Router Info parameter entry has associated LSA. */
-       SET_FLAG(OspfRI.flags, RIFLG_LSA_ENGAGED);
+       /* Install this LSA into LSDB. */
+       if (ospf_lsa_install(top, NULL /*oi */, new) == NULL) {
+               flog_warn(
+                       EC_OSPF_LSA_INSTALL_FAILURE,
+                       "RI (%s): ospf_lsa_install() ?", __func__);
+               ospf_lsa_unlock(&new);
+               return rc;
+       }
 
        /* Update new LSA origination count. */
        top->lsa_originate_count++;
 
-       /* Flood new LSA through AS. */
-       if (OspfRI.scope == OSPF_OPAQUE_AS_LSA)
-               ospf_flood_through_as(top, NULL /*nbr */, new);
-       else
-               ospf_flood_through_area(OspfRI.area, NULL /*nbr */, new);
+       /* Flood new LSA through AREA or AS. */
+       SET_FLAG(ai->flags, RIFLG_LSA_ENGAGED);
+       ospf_flood_through_area(ai->area, NULL /*nbr */, new);
 
        if (IS_DEBUG_OSPF(lsa, LSA_GENERATE)) {
                zlog_debug(
@@ -852,38 +913,62 @@ static int ospf_router_info_lsa_originate1(void *arg)
 static int ospf_router_info_lsa_originate(void *arg)
 {
 
+       struct ospf_ri_area_info *ai;
        int rc = -1;
 
        if (!OspfRI.enabled) {
-               zlog_info(
-                       "ospf_router_info_lsa_originate: ROUTER INFORMATION is disabled now.");
+               zlog_info("RI (%s): ROUTER INFORMATION is disabled now.",
+                         __func__);
                rc = 0; /* This is not an error case. */
                return rc;
        }
 
        /* Check if Router Information LSA is already engaged */
-       if (CHECK_FLAG(OspfRI.flags, RIFLG_LSA_ENGAGED)) {
-               if (CHECK_FLAG(OspfRI.flags, RIFLG_LSA_FORCED_REFRESH)) {
-                       UNSET_FLAG(OspfRI.flags, RIFLG_LSA_FORCED_REFRESH);
-                       ospf_router_info_lsa_schedule(REFRESH_THIS_LSA);
+       if (OspfRI.scope == OSPF_OPAQUE_AS_LSA) {
+               if ((CHECK_FLAG(OspfRI.as_flags, RIFLG_LSA_ENGAGED))
+                       && (CHECK_FLAG(OspfRI.as_flags,
+                               RIFLG_LSA_FORCED_REFRESH))) {
+                       UNSET_FLAG(OspfRI.as_flags, RIFLG_LSA_FORCED_REFRESH);
+                       ospf_router_info_lsa_schedule(NULL, REFRESH_THIS_LSA);
+                       rc = 0;
+                       return rc;
                }
        } else {
-               if (!is_mandated_params_set(OspfRI))
+               ai = lookup_by_area((struct ospf_area *)arg);
+               if (ai == NULL) {
                        flog_warn(
                                EC_OSPF_LSA,
-                               "ospf_router_info_lsa_originate: lacks mandated ROUTER INFORMATION parameters");
-
-               /* Ok, let's try to originate an LSA */
-               if (ospf_router_info_lsa_originate1(arg) != 0)
+                               "RI (%s): Missing area information", __func__);
                        return rc;
+               }
+               if ((CHECK_FLAG(ai->flags, RIFLG_LSA_ENGAGED))
+                       && (CHECK_FLAG(ai->flags, RIFLG_LSA_FORCED_REFRESH))) {
+                       UNSET_FLAG(ai->flags, RIFLG_LSA_FORCED_REFRESH);
+                       ospf_router_info_lsa_schedule(ai, REFRESH_THIS_LSA);
+                       rc = 0;
+                       return rc;
+               }
        }
 
-       rc = 0;
+       /* Router Information is not yet Engaged, check parameters */
+       if (!is_mandated_params_set(OspfRI))
+               flog_warn(
+                       EC_OSPF_LSA,
+                       "RI (%s): lacks mandated ROUTER INFORMATION parameters",
+                       __func__);
+
+       /* Ok, let's try to originate an LSA */
+       if (OspfRI.scope == OSPF_OPAQUE_AS_LSA)
+               rc = ospf_router_info_lsa_originate_as(arg);
+       else
+               rc = ospf_router_info_lsa_originate_area(arg);
+
        return rc;
 }
 
 static struct ospf_lsa *ospf_router_info_lsa_refresh(struct ospf_lsa *lsa)
 {
+       struct ospf_ri_area_info *ai = NULL;
        struct ospf_lsa *new = NULL;
        struct ospf *top;
 
@@ -893,8 +978,8 @@ static struct ospf_lsa *ospf_router_info_lsa_refresh(struct ospf_lsa *lsa)
                 * status change.
                 * It seems a slip among routers in the routing domain.
                 */
-               zlog_info(
-                       "ospf_router_info_lsa_refresh: ROUTER INFORMATION is disabled now.");
+               zlog_info("RI (%s): ROUTER INFORMATION is disabled now.",
+                         __func__);
                lsa->data->ls_age =
                        htons(OSPF_LSA_MAXAGE); /* Flush it anyway. */
        }
@@ -903,37 +988,66 @@ static struct ospf_lsa *ospf_router_info_lsa_refresh(struct ospf_lsa *lsa)
        if (GET_OPAQUE_ID(ntohl(lsa->data->id.s_addr)) != 0) {
                flog_warn(
                        EC_OSPF_LSA,
-                       "ospf_router_info_lsa_refresh: Unsupported Router Information ID");
+                       "RI (%s): Unsupported Router Information ID",
+                       __func__);
                return NULL;
        }
 
-       /* If the lsa's age reached to MaxAge, start flushing procedure. */
-       if (IS_LSA_MAXAGE(lsa)) {
-               UNSET_FLAG(OspfRI.flags, RIFLG_LSA_ENGAGED);
-               ospf_opaque_lsa_flush_schedule(lsa);
-               return NULL;
-       }
-
-       /* Create new Opaque-LSA/ROUTER INFORMATION instance. */
-       new = ospf_router_info_lsa_new();
-       new->data->ls_seqnum = lsa_seqnum_increment(lsa);
-       new->vrf_id = lsa->vrf_id;
-
-       /* Install this LSA into LSDB. */
-       /* Given "lsa" will be freed in the next function. */
-       top = ospf_lookup_by_vrf_id(lsa->vrf_id);
-       if (ospf_lsa_install(top, NULL /*oi */, new) == NULL) {
-               flog_warn(EC_OSPF_LSA_INSTALL_FAILURE,
-                         "ospf_router_info_lsa_refresh: ospf_lsa_install() ?");
-               ospf_lsa_unlock(&new);
-               return new;
-       }
-
-       /* Flood updated LSA through AS or AREA depending of OspfRI.scope. */
-       if (OspfRI.scope == OSPF_OPAQUE_AS_LSA)
+       /* Process LSA depending of the flooding scope */
+       if (OspfRI.scope == OSPF_OPAQUE_AREA_LSA) {
+               /* Get context AREA context */
+               ai = lookup_by_area(lsa->area);
+               if (ai == NULL) {
+                       flog_warn(
+                               EC_OSPF_LSA,
+                               "RI (%s): No associated Area", __func__);
+                       return NULL;
+               }
+               /* Flush LSA, if the lsa's age reached to MaxAge. */
+               if (IS_LSA_MAXAGE(lsa)) {
+                       UNSET_FLAG(ai->flags, RIFLG_LSA_ENGAGED);
+                       ospf_opaque_lsa_flush_schedule(lsa);
+                       return NULL;
+               }
+               /* Create new Opaque-LSA/ROUTER INFORMATION instance. */
+               new = ospf_router_info_lsa_new(ai->area);
+               new->data->ls_seqnum = lsa_seqnum_increment(lsa);
+               new->vrf_id = lsa->vrf_id;
+               /* Install this LSA into LSDB. */
+               /* Given "lsa" will be freed in the next function. */
+               top = ospf_lookup_by_vrf_id(lsa->vrf_id);
+               if (ospf_lsa_install(top, NULL /*oi */, new) == NULL) {
+                       flog_warn(EC_OSPF_LSA_INSTALL_FAILURE,
+                                 "RI (%s): ospf_lsa_install() ?", __func__);
+                       ospf_lsa_unlock(&new);
+                       return new;
+               }
+               /* Flood updated LSA through AREA */
+               ospf_flood_through_area(ai->area, NULL /*nbr */, new);
+
+       } else { /* AS Flooding scope */
+               /* Flush LSA, if the lsa's age reached to MaxAge. */
+               if (IS_LSA_MAXAGE(lsa)) {
+                       UNSET_FLAG(OspfRI.as_flags, RIFLG_LSA_ENGAGED);
+                       ospf_opaque_lsa_flush_schedule(lsa);
+                       return NULL;
+               }
+               /* Create new Opaque-LSA/ROUTER INFORMATION instance. */
+               new = ospf_router_info_lsa_new(NULL);
+               new->data->ls_seqnum = lsa_seqnum_increment(lsa);
+               new->vrf_id = lsa->vrf_id;
+               /* Install this LSA into LSDB. */
+               /* Given "lsa" will be freed in the next function. */
+               top = ospf_lookup_by_vrf_id(lsa->vrf_id);
+               if (ospf_lsa_install(top, NULL /*oi */, new) == NULL) {
+                       flog_warn(EC_OSPF_LSA_INSTALL_FAILURE,
+                                 "RI (%s): ospf_lsa_install() ?", __func__);
+                       ospf_lsa_unlock(&new);
+                       return new;
+               }
+               /* Flood updated LSA through AS */
                ospf_flood_through_as(top, NULL /*nbr */, new);
-       else
-               ospf_flood_through_area(OspfRI.area, NULL /*nbr */, new);
+       }
 
        /* Debug logging. */
        if (IS_DEBUG_OSPF(lsa, LSA_GENERATE)) {
@@ -946,7 +1060,8 @@ static struct ospf_lsa *ospf_router_info_lsa_refresh(struct ospf_lsa *lsa)
        return new;
 }
 
-static void ospf_router_info_lsa_schedule(enum lsa_opcode opcode)
+static void ospf_router_info_lsa_schedule(struct ospf_ri_area_info *ai,
+                                         enum lsa_opcode opcode)
 {
        struct ospf_lsa lsa;
        struct lsa_header lsah;
@@ -956,28 +1071,44 @@ static void ospf_router_info_lsa_schedule(enum lsa_opcode opcode)
        memset(&lsa, 0, sizeof(lsa));
        memset(&lsah, 0, sizeof(lsah));
 
-       zlog_debug("RI-> LSA schedule %s%s%s",
+       zlog_debug("RI (%s): LSA schedule %s%s%s", __func__,
                   opcode == REORIGINATE_THIS_LSA ? "Re-Originate" : "",
                   opcode == REFRESH_THIS_LSA ? "Refresh" : "",
                   opcode == FLUSH_THIS_LSA ? "Flush" : "");
 
-       /* Check LSA flags state coherence */
-       if (!CHECK_FLAG(OspfRI.flags, RIFLG_LSA_ENGAGED)
-           && (opcode != REORIGINATE_THIS_LSA))
-               return;
+       /* Check LSA flags state coherence and collect area information */
+       if (OspfRI.scope == OSPF_OPAQUE_AREA_LSA) {
+               if ((ai == NULL) || (ai->area == NULL)) {
+                       flog_warn(
+                               EC_OSPF_LSA,
+                               "RI (%s): Router Info is Area scope flooding but area is not set",
+                               __func__);
+                               return;
+               }
 
-       if (CHECK_FLAG(OspfRI.flags, RIFLG_LSA_ENGAGED)
-           && (opcode == REORIGINATE_THIS_LSA))
-               opcode = REFRESH_THIS_LSA;
+               if (!CHECK_FLAG(ai->flags, RIFLG_LSA_ENGAGED)
+                   && (opcode != REORIGINATE_THIS_LSA))
+                       return;
 
-       top = ospf_lookup_by_vrf_id(VRF_DEFAULT);
-       if ((OspfRI.scope == OSPF_OPAQUE_AREA_LSA) && (OspfRI.area == NULL)) {
-               flog_warn(
-                       EC_OSPF_LSA,
-                       "ospf_router_info_lsa_schedule(): Router Info is Area scope flooding but area is not set");
-               OspfRI.area = ospf_area_lookup_by_area_id(top, OspfRI.area_id);
+               if (CHECK_FLAG(ai->flags, RIFLG_LSA_ENGAGED)
+                   && (opcode == REORIGINATE_THIS_LSA))
+                       opcode = REFRESH_THIS_LSA;
+
+               lsa.area = ai->area;
+               top = ai->area->ospf;
+       } else {
+               if (!CHECK_FLAG(OspfRI.as_flags, RIFLG_LSA_ENGAGED)
+                   && (opcode != REORIGINATE_THIS_LSA))
+                       return;
+
+               if (CHECK_FLAG(OspfRI.as_flags, RIFLG_LSA_ENGAGED)
+                   && (opcode == REORIGINATE_THIS_LSA))
+                       opcode = REFRESH_THIS_LSA;
+
+               top = ospf_lookup_by_vrf_id(VRF_DEFAULT);
+               lsa.area = NULL;
        }
-       lsa.area = OspfRI.area;
+
        lsa.data = &lsah;
        lsah.type = OspfRI.scope;
 
@@ -989,7 +1120,7 @@ static void ospf_router_info_lsa_schedule(enum lsa_opcode opcode)
        case REORIGINATE_THIS_LSA:
                if (OspfRI.scope == OSPF_OPAQUE_AREA_LSA)
                        ospf_opaque_lsa_reoriginate_schedule(
-                               (void *)OspfRI.area, OSPF_OPAQUE_AREA_LSA,
+                               (void *)ai->area, OSPF_OPAQUE_AREA_LSA,
                                OPAQUE_TYPE_ROUTER_INFORMATION_LSA);
                else
                        ospf_opaque_lsa_reoriginate_schedule(
@@ -1000,7 +1131,10 @@ static void ospf_router_info_lsa_schedule(enum lsa_opcode opcode)
                ospf_opaque_lsa_refresh_schedule(&lsa);
                break;
        case FLUSH_THIS_LSA:
-               UNSET_FLAG(OspfRI.flags, RIFLG_LSA_ENGAGED);
+               if (OspfRI.scope == OSPF_OPAQUE_AREA_LSA)
+                       UNSET_FLAG(ai->flags, RIFLG_LSA_ENGAGED);
+               else
+                       UNSET_FLAG(OspfRI.as_flags, RIFLG_LSA_ENGAGED);
                ospf_opaque_lsa_flush_schedule(&lsa);
                break;
        }
@@ -1014,7 +1148,7 @@ static int ospf_router_info_lsa_update(struct ospf_lsa *lsa)
 
        /* Sanity Check */
        if (lsa == NULL) {
-               flog_warn(EC_OSPF_LSA, "OSPF-RI (%s): Abort! LSA is NULL",
+               flog_warn(EC_OSPF_LSA, "RI (%s): Abort! LSA is NULL",
                          __func__);
                return -1;
        }
@@ -1356,8 +1490,7 @@ static void ospf_router_info_config_write_router(struct vty *vty)
        if (OspfRI.scope == OSPF_OPAQUE_AS_LSA)
                vty_out(vty, " router-info as\n");
        else
-               vty_out(vty, " router-info area %s\n",
-                       inet_ntoa(OspfRI.area_id));
+               vty_out(vty, " router-info area\n");
 
        if (OspfRI.pce_info.enabled) {
 
@@ -1405,43 +1538,53 @@ static void ospf_router_info_config_write_router(struct vty *vty)
 /*------------------------------------------------------------------------*
  * Followings are vty command functions.
  *------------------------------------------------------------------------*/
+/* Simple wrapper schedule RI LSA action in function of the scope */
+static void ospf_router_info_schedule(enum lsa_opcode opcode)
+{
+       struct listnode *node, *nnode;
+       struct ospf_ri_area_info *ai;
+
+       if (OspfRI.scope == OSPF_OPAQUE_AS_LSA) {
+               if (CHECK_FLAG(OspfRI.as_flags, RIFLG_LSA_ENGAGED))
+                       ospf_router_info_lsa_schedule(NULL, opcode);
+               else if (opcode == REORIGINATE_THIS_LSA)
+                       ospf_router_info_lsa_schedule(NULL, opcode);
+       } else {
+               for (ALL_LIST_ELEMENTS(OspfRI.area_info, node, nnode, ai)) {
+                       if (CHECK_FLAG(ai->flags, RIFLG_LSA_ENGAGED))
+                               ospf_router_info_lsa_schedule(ai, opcode);
+               }
+       }
+}
 
 DEFUN (router_info,
        router_info_area_cmd,
-       "router-info <as|area A.B.C.D>",
+       "router-info <as|area [A.B.C.D]>",
        OSPF_RI_STR
        "Enable the Router Information functionality with AS flooding scope\n"
        "Enable the Router Information functionality with Area flooding scope\n"
-       "OSPF area ID in IP format\n")
+       "OSPF area ID in IP format (deprecated)\n")
 {
-       int idx_ipv4 = 2;
-       char *area = (argc == 3) ? argv[idx_ipv4]->arg : NULL;
-
+       int idx_mode = 1;
        uint8_t scope;
 
        if (OspfRI.enabled)
                return CMD_SUCCESS;
 
        /* Check and get Area value if present */
-       if (area) {
-               if (!inet_aton(area, &OspfRI.area_id)) {
-                       vty_out(vty, "%% specified Area ID %s is invalid\n",
-                               area);
-                       return CMD_WARNING_CONFIG_FAILED;
-               }
-               scope = OSPF_OPAQUE_AREA_LSA;
-       } else {
-               OspfRI.area_id.s_addr = 0;
+       if (strncmp(argv[idx_mode]->arg, "as", 2) == 0)
                scope = OSPF_OPAQUE_AS_LSA;
-       }
+       else
+               scope = OSPF_OPAQUE_AREA_LSA;
 
        /* First start to register Router Information callbacks */
-       if ((ospf_router_info_register(scope)) != 0) {
+       if (!OspfRI.registered && (ospf_router_info_register(scope)) != 0) {
                vty_out(vty,
                        "%% Unable to register Router Information callbacks.");
                flog_err(
                        EC_OSPF_INIT_FAIL,
-                       "Unable to register Router Information callbacks. Abort!");
+                       "RI (%s): Unable to register Router Information callbacks. Abort!",
+                       __func__);
                return CMD_WARNING_CONFIG_FAILED;
        }
 
@@ -1463,14 +1606,8 @@ DEFUN (router_info,
 
        initialize_params(&OspfRI);
 
-       /* Refresh RI LSA if already engaged */
-       if (CHECK_FLAG(OspfRI.flags, RIFLG_LSA_ENGAGED)) {
-               zlog_debug("RI-> Refresh LSA following configuration");
-               ospf_router_info_lsa_schedule(REFRESH_THIS_LSA);
-       } else {
-               zlog_debug("RI-> Initial origination following configuration");
-               ospf_router_info_lsa_schedule(REORIGINATE_THIS_LSA);
-       }
+       /* Originate or Refresh RI LSA if already engaged */
+       ospf_router_info_schedule(REORIGINATE_THIS_LSA);
        return CMD_SUCCESS;
 }
 
@@ -1488,8 +1625,7 @@ DEFUN (no_router_info,
        if (IS_DEBUG_OSPF_EVENT)
                zlog_debug("RI-> Router Information: ON -> OFF");
 
-       if (CHECK_FLAG(OspfRI.flags, RIFLG_LSA_ENGAGED))
-               ospf_router_info_lsa_schedule(FLUSH_THIS_LSA);
+       ospf_router_info_schedule(FLUSH_THIS_LSA);
 
        OspfRI.enabled = false;
 
@@ -1533,8 +1669,7 @@ DEFUN (pce_address,
                set_pce_address(value, pi);
 
                /* Refresh RI LSA if already engaged */
-               if (CHECK_FLAG(OspfRI.flags, RIFLG_LSA_ENGAGED))
-                       ospf_router_info_lsa_schedule(REFRESH_THIS_LSA);
+               ospf_router_info_schedule(REFRESH_THIS_LSA);
        }
 
        return CMD_SUCCESS;
@@ -1552,8 +1687,7 @@ DEFUN (no_pce_address,
        unset_param(&OspfRI.pce_info.pce_address);
 
        /* Refresh RI LSA if already engaged */
-       if (CHECK_FLAG(OspfRI.flags, RIFLG_LSA_ENGAGED))
-               ospf_router_info_lsa_schedule(REFRESH_THIS_LSA);
+       ospf_router_info_schedule(REFRESH_THIS_LSA);
 
        return CMD_SUCCESS;
 }
@@ -1583,8 +1717,7 @@ DEFUN (pce_path_scope,
                set_pce_path_scope(scope, pi);
 
                /* Refresh RI LSA if already engaged */
-               if (CHECK_FLAG(OspfRI.flags, RIFLG_LSA_ENGAGED))
-                       ospf_router_info_lsa_schedule(REFRESH_THIS_LSA);
+               ospf_router_info_schedule(REFRESH_THIS_LSA);
        }
 
        return CMD_SUCCESS;
@@ -1602,8 +1735,7 @@ DEFUN (no_pce_path_scope,
        unset_param(&OspfRI.pce_info.pce_address);
 
        /* Refresh RI LSA if already engaged */
-       if (CHECK_FLAG(OspfRI.flags, RIFLG_LSA_ENGAGED))
-               ospf_router_info_lsa_schedule(REFRESH_THIS_LSA);
+       ospf_router_info_schedule(REFRESH_THIS_LSA);
 
        return CMD_SUCCESS;
 }
@@ -1641,8 +1773,7 @@ DEFUN (pce_domain,
        set_pce_domain(PCE_DOMAIN_TYPE_AS, as, pce);
 
        /* Refresh RI LSA if already engaged */
-       if (CHECK_FLAG(OspfRI.flags, RIFLG_LSA_ENGAGED))
-               ospf_router_info_lsa_schedule(REFRESH_THIS_LSA);
+       ospf_router_info_schedule(REFRESH_THIS_LSA);
 
        return CMD_SUCCESS;
 }
@@ -1671,8 +1802,7 @@ DEFUN (no_pce_domain,
        unset_pce_domain(PCE_DOMAIN_TYPE_AS, as, pce);
 
        /* Refresh RI LSA if already engaged */
-       if (CHECK_FLAG(OspfRI.flags, RIFLG_LSA_ENGAGED))
-               ospf_router_info_lsa_schedule(REFRESH_THIS_LSA);
+       ospf_router_info_schedule(REFRESH_THIS_LSA);
 
        return CMD_SUCCESS;
 }
@@ -1711,8 +1841,7 @@ DEFUN (pce_neigbhor,
        set_pce_neighbor(PCE_DOMAIN_TYPE_AS, as, pce);
 
        /* Refresh RI LSA if already engaged */
-       if (CHECK_FLAG(OspfRI.flags, RIFLG_LSA_ENGAGED))
-               ospf_router_info_lsa_schedule(REFRESH_THIS_LSA);
+       ospf_router_info_schedule(REFRESH_THIS_LSA);
 
        return CMD_SUCCESS;
 }
@@ -1741,8 +1870,7 @@ DEFUN (no_pce_neighbor,
        unset_pce_neighbor(PCE_DOMAIN_TYPE_AS, as, pce);
 
        /* Refresh RI LSA if already engaged */
-       if (CHECK_FLAG(OspfRI.flags, RIFLG_LSA_ENGAGED))
-               ospf_router_info_lsa_schedule(REFRESH_THIS_LSA);
+       ospf_router_info_schedule(REFRESH_THIS_LSA);
 
        return CMD_SUCCESS;
 }
@@ -1773,8 +1901,7 @@ DEFUN (pce_cap_flag,
                set_pce_cap_flag(cap, pce);
 
                /* Refresh RI LSA if already engaged */
-               if (CHECK_FLAG(OspfRI.flags, RIFLG_LSA_ENGAGED))
-                       ospf_router_info_lsa_schedule(REFRESH_THIS_LSA);
+               ospf_router_info_schedule(REFRESH_THIS_LSA);
        }
 
        return CMD_SUCCESS;
@@ -1791,8 +1918,7 @@ DEFUN (no_pce_cap_flag,
        unset_param(&OspfRI.pce_info.pce_cap_flag);
 
        /* Refresh RI LSA if already engaged */
-       if (CHECK_FLAG(OspfRI.flags, RIFLG_LSA_ENGAGED))
-               ospf_router_info_lsa_schedule(REFRESH_THIS_LSA);
+       ospf_router_info_schedule(REFRESH_THIS_LSA);
 
        return CMD_SUCCESS;
 }