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 <olivier.dugeon@orange.com>
This commit is contained in:
Olivier Dugeon 2020-05-12 16:42:38 +02:00
parent 008bcff499
commit 21baf89aff
3 changed files with 201 additions and 16 deletions

View File

@ -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)))

View File

@ -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;
}

View File

@ -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);