diff --git a/doc/user/ospfd.rst b/doc/user/ospfd.rst index e843136396..b6a7cd5de0 100644 --- a/doc/user/ospfd.rst +++ b/doc/user/ospfd.rst @@ -979,14 +979,17 @@ Traffic Engineering Router Information ================== -.. index:: router-info [as | area ] -.. clicmd:: router-info [as | area ] +.. 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 ` 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 .. clicmd:: pce address diff --git a/ospfd/ospf_memory.c b/ospfd/ospf_memory.c index 1332104b0a..c4dc0136ed 100644 --- a/ospfd/ospf_memory.c +++ b/ospfd/ospf_memory.c @@ -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") diff --git a/ospfd/ospf_memory.h b/ospfd/ospf_memory.h index 50c6f33ecf..861de64c25 100644 --- a/ospfd/ospf_memory.h +++ b/ospfd/ospf_memory.h @@ -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) diff --git a/ospfd/ospf_ri.c b/ospfd/ospf_ri.c index bef16761f2..72f6dbe08e 100644 --- a/ospfd/ospf_ri.c +++ b/ospfd/ospf_ri.c @@ -59,60 +59,6 @@ #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 activate and initialize Router Information is necessary */ + /* 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; + } + + /* 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; } - /* Now this Router Info parameter entry has associated LSA. */ - SET_FLAG(OspfRI.flags, RIFLG_LSA_ENGAGED); + /* 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; + } + + /* 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; - } + /* 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); - /* 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) + } 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 ", + "router-info ", 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; } diff --git a/ospfd/ospf_ri.h b/ospfd/ospf_ri.h index 26bcc1b62a..84511ac5e7 100644 --- a/ospfd/ospf_ri.h +++ b/ospfd/ospf_ri.h @@ -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. */