]> git.proxmox.com Git - mirror_frr.git/commitdiff
OSPF: Add support to multi-area to Router Info.
authorOlivier Dugeon <olivier.dugeon@orange.com>
Fri, 26 Oct 2018 17:12:41 +0000 (19:12 +0200)
committerPhilippe Guibert <philippe.guibert@6wind.com>
Fri, 9 Nov 2018 09:09:47 +0000 (10:09 +0100)
  Router Information needs to specify the area ID when flooding scope is set to
  AREA. However, this authorize only one AREA. Thus, Area Border Router (ABR) are
  unable to flood Router Information Opaque LSA in all areas they are belongs to.

  The path implies that the area ID is no more necessary for the command
  'router-info area'. It remains suported for compatibility, but mark as
  deprecated. Documentation has been updated accordingly.

Signed-off-by: Olivier Dugeon <olivier.dugeon@orange.com>
doc/user/ospfd.rst
ospfd/ospf_memory.c
ospfd/ospf_memory.h
ospfd/ospf_ri.c
ospfd/ospf_ri.h

index e84313639659e9fe1dceaafaa1ecd26d2fd11118..b6a7cd5de03e172e7e62b077bbda273570644b48 100644 (file)
@@ -979,14 +979,17 @@ Traffic Engineering
 Router Information
 ==================
 
-.. index:: router-info [as | area <A.B.C.D>]
-.. clicmd:: router-info [as | area <A.B.C.D>]
+.. index:: router-info [as | area]
+.. clicmd:: router-info [as | area]
 
 .. index:: no router-info
 .. clicmd:: no router-info
 
    Enable Router Information (:rfc:`4970`) LSA advertisement with AS scope
-   (default) or Area scope flooding when area is specified.
+   (default) or Area scope flooding when area is specified. Old syntax
+   `router-info area <A.B.C.D>` is always supported but mark as deprecated
+   as the area ID is no more necessary. Indeed, router information support
+   multi-area and detect automatically the areas.
 
 .. index:: pce address <A.B.C.D>
 .. clicmd:: pce address <A.B.C.D>
index 1332104b0afdd6a384f2b1cf6ff14a4785107d7c..c4dc0136edaeae7b512ba9cd8e9fe5360c83cf14 100644 (file)
@@ -52,6 +52,7 @@ DEFINE_MTYPE(OSPFD, OSPF_IF_INFO, "OSPF if info")
 DEFINE_MTYPE(OSPFD, OSPF_IF_PARAMS, "OSPF if params")
 DEFINE_MTYPE(OSPFD, OSPF_MESSAGE, "OSPF message")
 DEFINE_MTYPE(OSPFD, OSPF_MPLS_TE, "OSPF MPLS parameters")
+DEFINE_MTYPE(OSPFD, OSPF_ROUTER_INFO, "OSPF Router Info parameters")
 DEFINE_MTYPE(OSPFD, OSPF_PCE_PARAMS, "OSPF PCE parameters")
 DEFINE_MTYPE(OSPFD, OSPF_EXT_PARAMS, "OSPF Extended parameters")
 DEFINE_MTYPE(OSPFD, OSPF_SR_PARAMS, "OSPF Segment Routing parameters")
index 50c6f33ecfbc4c5d03ab4747d9c8c5461f96573b..861de64c25d3f0de9869af16832026c6308b5208 100644 (file)
@@ -51,6 +51,7 @@ DECLARE_MTYPE(OSPF_IF_INFO)
 DECLARE_MTYPE(OSPF_IF_PARAMS)
 DECLARE_MTYPE(OSPF_MESSAGE)
 DECLARE_MTYPE(OSPF_MPLS_TE)
+DECLARE_MTYPE(OSPF_ROUTER_INFO)
 DECLARE_MTYPE(OSPF_PCE_PARAMS)
 DECLARE_MTYPE(OSPF_SR_PARAMS)
 DECLARE_MTYPE(OSPF_EXT_PARAMS)
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;
 }
index 26bcc1b62a9d92f32a7a49d36fe400ff71bd23ca..84511ac5e78161851e020fceced60fb8de41f1cd 100644 (file)
@@ -170,7 +170,71 @@ struct ri_pce_subtlv_cap_flag {
 /* Structure to share flooding scope info for Segment Routing */
 struct scope_info {
        uint8_t scope;
-       struct in_addr area_id;
+       struct list *areas;
+};
+
+/* Flags to manage the Router Information LSA. */
+#define RIFLG_LSA_INACTIVE             0x0
+#define RIFLG_LSA_ENGAGED              0x1
+#define RIFLG_LSA_FORCED_REFRESH       0x2
+
+/* 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;
+};
+
+/* Store area information to flood LSA per area */
+struct ospf_ri_area_info {
+
+       uint32_t flags;
+
+       /* area pointer if flooding is Type 10 Null if flooding is AS scope */
+       struct ospf_area *area;
+};
+
+/* Following structure are internal use only. */
+struct ospf_router_info {
+       bool enabled;
+
+       uint8_t registered;
+       uint8_t scope;
+       /* LSA flags are only used when scope is AS flooding */
+       uint32_t as_flags;
+
+       /* List of area info to flood RI LSA */
+       struct list *area_info;
+
+       /* 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;
 };
 
 /* Prototypes. */