From 21baf89affbcffdd02fd557e81d16b80850266ca Mon Sep 17 00:00:00 2001 From: Olivier Dugeon Date: Tue, 12 May 2020 16:42:38 +0200 Subject: [PATCH] ospfd: Update Prefix & Adjacency SIDs Management SIDs are not uninstall in LFIB when ospf adjacenyi or loopback goes down as self LSA flusing is not handle by ospf_ext_link_lsa_update(). The patch introduces new functions ospf_sr_ext_itf_add() and ospf_sr_ext_itf_delete() in ospf_sr.c to directly manage LFIB for SIDs when change is detected in ospf_ext_link_ism_change() and ospf_ext_link_nsm_change(). Signed-off-by: Olivier Dugeon --- ospfd/ospf_ext.c | 75 ++++++++++++++++++++++---- ospfd/ospf_sr.c | 138 ++++++++++++++++++++++++++++++++++++++++++++--- ospfd/ospf_sr.h | 4 ++ 3 files changed, 201 insertions(+), 16 deletions(-) diff --git a/ospfd/ospf_ext.c b/ospfd/ospf_ext.c index 14f38bc330..86088a7137 100644 --- a/ospfd/ospf_ext.c +++ b/ospfd/ospf_ext.c @@ -443,6 +443,32 @@ static void set_rmt_itf_addr(struct ext_itf *exti, struct in_addr rmtif) exti->rmt_itf_addr.value = rmtif; } +/* Delete Extended LSA */ +static void ospf_extended_lsa_delete(struct ext_itf *exti) +{ + + /* Process only Active Extended Prefix/Link LSA */ + if (!CHECK_FLAG(exti->flags, EXT_LPFLG_LSA_ACTIVE)) + return; + + osr_debug("EXT (%s): Disable %s%s%s-SID on interface %s", __func__, + exti->stype == PREF_SID ? "Prefix" : "", + exti->stype == ADJ_SID ? "Adjacency" : "", + exti->stype == LAN_ADJ_SID ? "LAN-Adjacency" : "", + exti->ifp->name); + + /* Flush LSA if already engaged */ + if (CHECK_FLAG(exti->flags, EXT_LPFLG_LSA_ENGAGED)) { + ospf_ext_lsa_schedule(exti, FLUSH_THIS_LSA); + UNSET_FLAG(exti->flags, EXT_LPFLG_LSA_ENGAGED); + } + + /* De-activate this Extended Prefix/Link and remove corresponding + * Segment-Routing Prefix-SID or (LAN)-ADJ-SID */ + exti->flags = EXT_LPFLG_LSA_INACTIVE; + ospf_sr_ext_itf_delete(exti); +} + /* * Update Extended prefix SID index for Loopback interface type * @@ -516,6 +542,7 @@ void ospf_ext_update_sr(bool enable) /* Refresh LSAs if already engaged or originate */ for (ALL_LIST_ELEMENTS_RO(OspfEXT.iflist, node, exti)) { + /* Skip inactive Extended Link */ if (!CHECK_FLAG(exti->flags, EXT_LPFLG_LSA_ACTIVE)) continue; @@ -526,17 +553,15 @@ void ospf_ext_update_sr(bool enable) REORIGINATE_THIS_LSA); } } else { - /* Start by Flushing engaged LSAs */ - for (ALL_LIST_ELEMENTS_RO(OspfEXT.iflist, node, exti)) { - if (CHECK_FLAG(exti->flags, EXT_LPFLG_LSA_ENGAGED)) - ospf_ext_lsa_schedule(exti, FLUSH_THIS_LSA); - exti->flags = EXT_LPFLG_LSA_INACTIVE; - } + /* Start by Removing Extended LSA */ + for (ALL_LIST_ELEMENTS_RO(OspfEXT.iflist, node, exti)) + ospf_extended_lsa_delete(exti); /* And then disable Extended Link/Prefix */ OspfEXT.enabled = false; } } + /* * ----------------------------------------------------------------------- * Followings are callback functions against generic Opaque-LSAs handling @@ -574,10 +599,11 @@ static int ospf_ext_link_del_if(struct interface *ifp) exti = lookup_ext_by_ifp(ifp); if (exti != NULL) { - struct list *iflist = OspfEXT.iflist; + /* Flush LSA and remove Adjacency SID */ + ospf_extended_lsa_delete(exti); /* Dequeue listnode entry from the list. */ - listnode_delete(iflist, exti); + listnode_delete(OspfEXT.iflist, exti); XFREE(MTYPE_OSPF_EXT_PARAMS, exti); @@ -610,6 +636,7 @@ static void ospf_ext_ism_change(struct ospf_interface *oi, int old_status) /* Reset Extended information if ospf interface goes Down */ if (oi->state == ISM_Down) { + ospf_extended_lsa_delete(exti); exti->area = NULL; exti->flags = EXT_LPFLG_LSA_INACTIVE; return; @@ -660,8 +687,8 @@ static void ospf_ext_link_nsm_change(struct ospf_neighbor *nbr, int old_status) struct ext_itf *exti; uint32_t label; - /* Process Neighbor only when its state is NSM Full */ - if (nbr->state != NSM_Full) + /* Process Link only when neighbor old or new state is NSM Full */ + if (nbr->state != NSM_Full && old_status != NSM_Full) return; /* Get interface information for Segment Routing */ @@ -673,6 +700,23 @@ static void ospf_ext_link_nsm_change(struct ospf_neighbor *nbr, int old_status) return; } + /* Check that we have a valid area and ospf context */ + if (oi->area == NULL || oi->area->ospf == NULL) { + flog_warn(EC_OSPF_EXT_LSA_UNEXPECTED, + "EXT (%s): Cannot refer to OSPF from OI(%s)", + __func__, IF_NAME(oi)); + return; + } + + /* Remove Extended Link if Neighbor State goes Down or Deleted */ + if (nbr->state == NSM_Down || nbr->state == NSM_Deleted) { + ospf_extended_lsa_delete(exti); + return; + } + + /* Keep Area information in combination with SR info. */ + exti->area = oi->area; + /* Process only Adjacency/LAN SID */ if (exti->stype == PREF_SID) return; @@ -748,6 +792,9 @@ static void ospf_ext_link_nsm_change(struct ospf_neighbor *nbr, int old_status) else ospf_ext_link_lsa_schedule(exti, REORIGINATE_THIS_LSA); } + + /* Finally install (LAN)Adjacency-SID in the SRDB */ + ospf_sr_ext_itf_add(exti); } /* Callbacks to handle Extended Link Segment Routing LSA information */ @@ -770,6 +817,10 @@ static int ospf_ext_link_lsa_update(struct ospf_lsa *lsa) != OPAQUE_TYPE_EXTENDED_LINK_LSA) return 0; + /* Check if it is not my LSA */ + if (IS_LSA_SELF(lsa)) + return 0; + /* Check if Extended is enable */ if (!OspfEXT.enabled) return 0; @@ -1218,6 +1269,10 @@ static int ospf_ext_link_lsa_originate(void *arg) if (exti->stype == PREF_SID) continue; + /* Skip Inactive Extended Link */ + if (!CHECK_FLAG(exti->flags, EXT_LPFLG_LSA_ACTIVE)) + continue; + /* Process only Extended Link with valid Area ID */ if ((exti->area == NULL) || (!IPV4_ADDR_SAME(&exti->area->area_id, &area->area_id))) diff --git a/ospfd/ospf_sr.c b/ospfd/ospf_sr.c index 33d994c79c..d92968644d 100644 --- a/ospfd/ospf_sr.c +++ b/ospfd/ospf_sr.c @@ -286,6 +286,8 @@ static void ospf_sr_stop(void) * be remove though list_delete() call. See sr_node_del() */ hash_clean(OspfSR.neighbors, (void *)sr_node_del); + OspfSR.self = NULL; + OspfSR.enabled = false; } /* @@ -352,9 +354,6 @@ void ospf_sr_term(void) /* Clear Prefix Table */ if (OspfSR.prefix) route_table_finish(OspfSR.prefix); - - OspfSR.enabled = false; - OspfSR.self = NULL; } /* @@ -367,8 +366,6 @@ void ospf_sr_finish(void) { /* Stop Segment Routing */ ospf_sr_stop(); - - OspfSR.enabled = false; } /* @@ -1345,6 +1342,136 @@ void ospf_sr_ext_link_lsa_delete(struct ospf_lsa *lsa) } } +/* Add (LAN)Adjacency-SID from Extended Link Information */ +void ospf_sr_ext_itf_add(struct ext_itf *exti) +{ + struct sr_node *srn = OspfSR.self; + struct sr_link *srl; + + osr_debug("SR (%s): Add Extended Link LSA 8.0.0.%u from self", __func__, + exti->instance); + + /* Sanity check */ + if (srn == NULL) + return; + + /* Initialize new Segment Routing Link */ + srl = XCALLOC(MTYPE_OSPF_SR_PARAMS, sizeof(struct sr_link)); + srl->srn = srn; + srl->adv_router = srn->adv_router; + srl->itf_addr = exti->link.link_data; + srl->instance = + SET_OPAQUE_LSID(OPAQUE_TYPE_EXTENDED_LINK_LSA, exti->instance); + switch (exti->stype) { + case ADJ_SID: + srl->type = ADJ_SID; + /* Primary information */ + srl->flags[0] = exti->adj_sid[0].flags; + if (CHECK_FLAG(exti->adj_sid[0].flags, + EXT_SUBTLV_LINK_ADJ_SID_VFLG)) + srl->sid[0] = GET_LABEL(ntohl(exti->adj_sid[0].value)); + else + srl->sid[0] = ntohl(exti->adj_sid[0].value); + if (exti->rmt_itf_addr.header.type == 0) + srl->nhlfe[0].nexthop = exti->link.link_id; + else + srl->nhlfe[0].nexthop = exti->rmt_itf_addr.value; + /* Backup Information if set */ + if (exti->adj_sid[1].header.type == 0) + break; + srl->flags[1] = exti->adj_sid[1].flags; + if (CHECK_FLAG(exti->adj_sid[1].flags, + EXT_SUBTLV_LINK_ADJ_SID_VFLG)) + srl->sid[1] = GET_LABEL(ntohl(exti->adj_sid[1].value)); + else + srl->sid[1] = ntohl(exti->adj_sid[1].value); + if (exti->rmt_itf_addr.header.type == 0) + srl->nhlfe[1].nexthop = exti->link.link_id; + else + srl->nhlfe[1].nexthop = exti->rmt_itf_addr.value; + break; + case LAN_ADJ_SID: + srl->type = LAN_ADJ_SID; + /* Primary information */ + srl->flags[0] = exti->lan_sid[0].flags; + if (CHECK_FLAG(exti->lan_sid[0].flags, + EXT_SUBTLV_LINK_ADJ_SID_VFLG)) + srl->sid[0] = GET_LABEL(ntohl(exti->lan_sid[0].value)); + else + srl->sid[0] = ntohl(exti->lan_sid[0].value); + if (exti->rmt_itf_addr.header.type == 0) + srl->nhlfe[0].nexthop = exti->lan_sid[0].neighbor_id; + else + srl->nhlfe[0].nexthop = exti->rmt_itf_addr.value; + /* Backup Information if set */ + if (exti->lan_sid[1].header.type == 0) + break; + srl->flags[1] = exti->lan_sid[1].flags; + if (CHECK_FLAG(exti->lan_sid[1].flags, + EXT_SUBTLV_LINK_ADJ_SID_VFLG)) + srl->sid[1] = GET_LABEL(ntohl(exti->lan_sid[1].value)); + else + srl->sid[1] = ntohl(exti->lan_sid[1].value); + if (exti->rmt_itf_addr.header.type == 0) + srl->nhlfe[1].nexthop = exti->lan_sid[1].neighbor_id; + else + srl->nhlfe[1].nexthop = exti->rmt_itf_addr.value; + break; + default: + /* Wrong SID Type. Abort! */ + XFREE(MTYPE_OSPF_SR_PARAMS, srl); + return; + } + + /* Segment Routing Link is ready, update it */ + update_ext_link_sid(srn, srl, OSPF_LSA_SELF); +} + +/* Delete Prefix or (LAN)Adjacency-SID from Extended Link Information */ +void ospf_sr_ext_itf_delete(struct ext_itf *exti) +{ + struct listnode *node; + struct sr_node *srn = OspfSR.self; + struct sr_prefix *srp = NULL; + struct sr_link *srl = NULL; + uint32_t instance; + + osr_debug("SR (%s): Remove Extended LSA %u.0.0.%u from self", + __func__, exti->stype == PREF_SID ? 7 : 8, exti->instance); + + /* Sanity check: SR-Node and Extended Prefix/Link list may have been + * removed earlier when stopping OSPF or OSPF-SR */ + if (srn == NULL || srn->ext_prefix == NULL || srn->ext_link == NULL) + return; + + if (exti->stype == PREF_SID) { + instance = SET_OPAQUE_LSID(OPAQUE_TYPE_EXTENDED_PREFIX_LSA, + exti->instance); + for (ALL_LIST_ELEMENTS_RO(srn->ext_prefix, node, srp)) + if (srp->instance == instance) + break; + + /* Uninstall Segment Prefix SID if found */ + if ((srp != NULL) && (srp->instance == instance)) + delete_prefix_sid(srp); + } else { + /* Search for corresponding Segment Link for self SR-Node */ + instance = SET_OPAQUE_LSID(OPAQUE_TYPE_EXTENDED_LINK_LSA, + exti->instance); + for (ALL_LIST_ELEMENTS_RO(srn->ext_link, node, srl)) + if (srl->instance == instance) + break; + + /* Remove Segment Link if found */ + if ((srl != NULL) && (srl->instance == instance)) { + del_adj_sid(srl->nhlfe[0]); + del_adj_sid(srl->nhlfe[1]); + listnode_delete(srn->ext_link, srl); + XFREE(MTYPE_OSPF_SR_PARAMS, srl); + } + } +} + /* Update Segment Routing from Extended Prefix LSA */ void ospf_sr_ext_prefix_lsa_update(struct ospf_lsa *lsa) { @@ -1700,7 +1827,6 @@ DEFUN (no_ospf_sr_enable, /* Finally, stop Segment Routing */ ospf_sr_stop(); - OspfSR.enabled = false; return CMD_SUCCESS; } diff --git a/ospfd/ospf_sr.h b/ospfd/ospf_sr.h index d03da71108..5e1e1f7837 100644 --- a/ospfd/ospf_sr.h +++ b/ospfd/ospf_sr.h @@ -312,6 +312,10 @@ extern void ospf_sr_ext_link_lsa_update(struct ospf_lsa *lsa); extern void ospf_sr_ext_link_lsa_delete(struct ospf_lsa *lsa); extern void ospf_sr_ext_prefix_lsa_update(struct ospf_lsa *lsa); extern void ospf_sr_ext_prefix_lsa_delete(struct ospf_lsa *lsa); +/* Segment Routing Extending Link management */ +struct ext_itf; +extern void ospf_sr_ext_itf_add(struct ext_itf *exti); +extern void ospf_sr_ext_itf_delete(struct ext_itf *exti); /* Segment Routing configuration functions */ extern uint32_t get_ext_link_label_value(void); extern void ospf_sr_config_write_router(struct vty *vty);