X-Git-Url: https://git.proxmox.com/?a=blobdiff_plain;f=ospfd%2Fospf_ri.c;h=72f6dbe08e220c95e43bf38e1f3cb7f191a140af;hb=2569910bb6e5c00ececc60ed15b182e14a88cb9d;hp=e95fc43aabe3916ccfe2c89d4377023ad1f07bcf;hpb=b4657ea44c7853047fa21585defd06b4b2e52752;p=mirror_frr.git diff --git a/ospfd/ospf_ri.c b/ospfd/ospf_ri.c index e95fc43aa..72f6dbe08 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; } @@ -217,8 +166,8 @@ static int ospf_router_info_unregister() void ospf_router_info_term(void) { - list_delete_and_null(&OspfRI.pce_info.pce_domain); - list_delete_and_null(&OspfRI.pce_info.pce_neighbor); + list_delete(&OspfRI.pce_info.pce_domain); + list_delete(&OspfRI.pce_info.pce_neighbor); OspfRI.enabled = false; @@ -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. @@ -380,10 +345,6 @@ static void unset_pce_domain(uint16_t type, uint32_t domain, if (found) { listnode_delete(pce->pce_domain, old); - /* Avoid misjudgement in the next lookup. */ - if (listcount(pce->pce_domain) == 0) - pce->pce_domain->head = pce->pce_domain->tail = NULL; - /* Finally free the old domain */ XFREE(MTYPE_OSPF_PCE_PARAMS, old); } @@ -430,11 +391,6 @@ static void unset_pce_neighbor(uint16_t type, uint32_t domain, if (found) { listnode_delete(pce->pce_neighbor, old); - /* Avoid misjudgement in the next lookup. */ - if (listcount(pce->pce_neighbor) == 0) - pce->pce_neighbor->head = pce->pce_neighbor->tail = - NULL; - /* Finally free the old domain */ XFREE(MTYPE_OSPF_PCE_PARAMS, old); } @@ -534,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. @@ -545,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 @@ -600,22 +567,37 @@ static int is_mandated_params_set(struct ospf_router_info ori) * @param enable To activate or not Segment Routing router Information flooding * @param size Size of Label Range i.e. SRGB size * @param lower Lower bound of the Label Range i.e. SRGB first label - * @param msd Maximum label Stack Depth suported by the router + * @param msd Maximum label Stack Depth supported by the router * * @return none */ 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) { @@ -635,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); + + } } /*------------------------------------------------------------------------* @@ -647,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; } @@ -732,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; @@ -777,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; @@ -792,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; } @@ -830,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( @@ -861,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; @@ -902,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. */ } @@ -912,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"); - 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); + "RI (%s): Unsupported Router Information ID", + __func__); 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)) { @@ -955,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; @@ -965,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; @@ -998,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( @@ -1009,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; } @@ -1023,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; } @@ -1365,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) { @@ -1414,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; } @@ -1472,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; } @@ -1497,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; @@ -1542,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; @@ -1561,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; } @@ -1592,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; @@ -1611,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; } @@ -1650,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; } @@ -1680,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; } @@ -1720,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; } @@ -1750,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; } @@ -1782,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; @@ -1800,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; }