ospfd: Add Segment Routing Local Block

RFC 8665 defines a Segment Routing Local Block for Adjacency SID.
This patch provides the possibility to modify the SRLB as well as
reserved the block range from the Label Manager.

 - Introduce new CLI 'segment-routing local-block'
 - Add local block to SRDB structure
 - Parse / Serialize SRLB in Router Information LSA
 - Update OSPF-SR topotest
 - Update documentation

Signed-off-by: Olivier Dugeon <olivier.dugeon@orange.com>
This commit is contained in:
Olivier Dugeon 2020-06-18 19:46:28 +02:00
parent d81b8e0e1a
commit 6f751f1493
19 changed files with 792 additions and 204 deletions

View File

@ -1,8 +1,7 @@
OSPF Segment Routing
====================
This is an EXPERIMENTAL support of draft
`draft-ietf-ospf-segment-routing-extensions-24`.
This is an EXPERIMENTAL support of `RFC 8665`.
DON'T use it for production network.
Supported Features
@ -10,12 +9,13 @@ Supported Features
* Automatic computation of Primary and Backup Adjacency SID with
Cisco experimental remote IP address
* SRGB configuration
* SRGB & SRLB configuration
* Prefix configuration for Node SID with optional NO-PHP flag (Linux
kernel support both mode)
* Node MSD configuration (with Linux Kernel >= 4.10 a maximum of 32 labels
could be stack)
* Automatic provisioning of MPLS table
* Equal Cost Multi-Path (ECMP)
* Static route configuration with label stack up to 32 labels
Interoperability
@ -243,16 +243,16 @@ Routing.
router ospf
ospf router-id 192.168.1.11
capability opaque
mpls-te on
mpls-te router-address 192.168.1.11
router-info area 0.0.0.0
segment-routing on
segment-routing global-block 10000 19999
segment-routing local-block 5000 5999
segment-routing node-msd 8
segment-routing prefix 192.168.1.11/32 index 1100
The first segment-routing statement enable it. The Second one set the SRGB,
third line the MSD and finally, set the Prefix SID index for a given prefix.
The first segment-routing statement enables it. The second and third one set
the SRGB and SRLB respectively, fourth line the MSD and finally, set the
Prefix SID index for a given prefix.
Note that only prefix of Loopback interface could be configured with a Prefix
SID. It is possible to add `no-php-flag` at the end of the prefix command to
disable Penultimate Hop Popping. This advertises to peers that they MUST NOT pop
@ -265,9 +265,6 @@ Known limitations
* Only single Area is supported. ABR is not yet supported
* Only SPF algorithm is supported
* Extended Prefix Range is not supported
* MPLS table are not flush at startup. Thus, restarting zebra process is
mandatory to remove old MPLS entries in the data plane after a crash of
ospfd daemon
* With NO Penultimate Hop Popping, it is not possible to express a Segment
Path with an Adjacency SID due to the impossibility for the Linux Kernel to
perform double POP instruction.

View File

@ -1071,8 +1071,8 @@ Router Information
Segment Routing
===============
This is an EXPERIMENTAL support of Segment Routing as per draft
`draft-ietf-ospf-segment-routing-extensions-24.txt` for MPLS dataplane.
This is an EXPERIMENTAL support of Segment Routing as per `RFC 8665` for MPLS
dataplane.
.. index:: [no] segment-routing on
.. clicmd:: [no] segment-routing on
@ -1085,7 +1085,13 @@ This is an EXPERIMENTAL support of Segment Routing as per draft
.. clicmd:: [no] segment-routing global-block (0-1048575) (0-1048575)
Fix the Segment Routing Global Block i.e. the label range used by MPLS to
store label in the MPLS FIB.
store label in the MPLS FIB for Prefix SID.
.. index:: [no] segment-routing local-block (0-1048575) (0-1048575)
.. clicmd:: [no] segment-routing local-block (0-1048575) (0-1048575)
Fix the Segment Routing Local Block i.e. the label range used by MPLS to
store label in the MPLS FIB for Adjacency SID.
.. index:: [no] segment-routing node-msd (1-16)
.. clicmd:: [no] segment-routing node-msd (1-16)

View File

@ -157,6 +157,12 @@ static struct log_ref ferr_ospf_err[] = {
.description = "OSPF Segment Routing invalid lsa id",
.suggestion = "Restart OSPF instance, If the problem persists, report the problem for troubleshooting"
},
{
.code = EC_OSPF_SR_SID_OVERFLOW,
.title = "OSPF SR Segment-ID overflow",
.description = "OSPF Segment Routing ID index or label exceed Global or Local Block Range",
.suggestion = "Restart OSPF instance, If the problem persists, report the problem for troubleshooting"
},
{
.code = EC_OSPF_INVALID_ALGORITHM,
.title = "OSPF SR Invalid Algorithm",

View File

@ -31,6 +31,7 @@ enum ospf_log_refs {
EC_OSPF_SR_INVALID_DB,
EC_OSPF_SR_NODE_CREATE,
EC_OSPF_SR_INVALID_LSA_ID,
EC_OSPF_SR_SID_OVERFLOW,
EC_OSPF_INVALID_ALGORITHM,
EC_OSPF_FSM_INVALID_STATE,
EC_OSPF_SET_METRIC_PLUS,

View File

@ -98,6 +98,7 @@ static void ospf_ext_link_lsa_schedule(struct ext_itf *exti,
static void ospf_ext_lsa_schedule(struct ext_itf *exti, enum lsa_opcode op);
static int ospf_ext_link_lsa_update(struct ospf_lsa *lsa);
static int ospf_ext_pref_lsa_update(struct ospf_lsa *lsa);
static void ospf_ext_link_delete_adj_sid(struct ext_itf *exti);
static void del_ext_info(void *val);
/*
@ -434,6 +435,20 @@ static void set_lan_adj_sid(struct ext_itf *exti, bool backup, uint32_t value,
exti->lan_sid[index].neighbor_id = neighbor_id;
}
static void unset_adjacency_sid(struct ext_itf *exti)
{
/* Reset Adjacency TLV */
if (exti->type == ADJ_SID) {
TLV_TYPE(exti->adj_sid[0]) = 0;
TLV_TYPE(exti->adj_sid[1]) = 0;
}
/* or Lan-Adjacency TLV */
if (exti->type == LAN_ADJ_SID) {
TLV_TYPE(exti->lan_sid[0]) = 0;
TLV_TYPE(exti->lan_sid[1]) = 0;
}
}
/* Experimental SubTLV from Cisco */
static void set_rmt_itf_addr(struct ext_itf *exti, struct in_addr rmtif)
{
@ -452,7 +467,7 @@ static void ospf_extended_lsa_delete(struct ext_itf *exti)
return;
osr_debug("EXT (%s): Disable %s%s%s-SID on interface %s", __func__,
exti->stype == PREF_SID ? "Prefix" : "",
exti->stype == LOCAL_SID ? "Prefix" : "",
exti->stype == ADJ_SID ? "Adjacency" : "",
exti->stype == LAN_ADJ_SID ? "LAN-Adjacency" : "",
exti->ifp->name);
@ -465,8 +480,10 @@ static void ospf_extended_lsa_delete(struct ext_itf *exti)
/* 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);
if (exti->stype == ADJ_SID || exti->stype == LAN_ADJ_SID)
ospf_ext_link_delete_adj_sid(exti);
else
ospf_sr_ext_itf_delete(exti);
}
/*
@ -521,6 +538,97 @@ uint32_t ospf_ext_schedule_prefix_index(struct interface *ifp, uint32_t index,
return SET_OPAQUE_LSID(exti->type, exti->instance);
}
/**
* Update Adjacecny-SID for Extended Link LSA
*
* @param exti Extended Link information
*/
static void ospf_ext_link_update_adj_sid(struct ext_itf *exti)
{
mpls_label_t label;
mpls_label_t bck_label;
/* Process only (LAN)Adjacency-SID Type */
if (exti->stype != ADJ_SID && exti->stype != LAN_ADJ_SID)
return;
/* Request Primary & Backup Labels from Label Manager */
bck_label = ospf_sr_local_block_request_label();
label = ospf_sr_local_block_request_label();
if (bck_label == MPLS_INVALID_LABEL || label == MPLS_INVALID_LABEL) {
if (CHECK_FLAG(exti->flags, EXT_LPFLG_LSA_ENGAGED))
ospf_ext_lsa_schedule(exti, FLUSH_THIS_LSA);
return;
}
/* Set Adjacency-SID, backup first */
if (exti->stype == ADJ_SID) {
set_adj_sid(exti, true, bck_label, SID_LABEL);
set_adj_sid(exti, false, label, SID_LABEL);
} else {
set_lan_adj_sid(exti, true, bck_label, SID_LABEL,
exti->lan_sid[0].neighbor_id);
set_lan_adj_sid(exti, false, label, SID_LABEL,
exti->lan_sid[1].neighbor_id);
}
/* Finally, add corresponding SR Link in SRDB & MPLS LFIB */
SET_FLAG(exti->flags, EXT_LPFLG_FIB_ENTRY_SET);
ospf_sr_ext_itf_add(exti);
}
/**
* Delete Adjacecny-SID for Extended Link LSA
*
* @param exti Extended Link information
*/
static void ospf_ext_link_delete_adj_sid(struct ext_itf *exti)
{
/* Process only (LAN)Adjacency-SID Type */
if (exti->stype != ADJ_SID && exti->stype != LAN_ADJ_SID)
return;
/* Release Primary & Backup Labels from Label Manager */
if (exti->stype == ADJ_SID) {
ospf_sr_local_block_release_label(exti->adj_sid[0].value);
ospf_sr_local_block_release_label(exti->adj_sid[1].value);
} else {
ospf_sr_local_block_release_label(exti->adj_sid[0].value);
ospf_sr_local_block_release_label(exti->adj_sid[1].value);
}
/* And reset corresponding TLV */
unset_adjacency_sid(exti);
/* Finally, remove corresponding SR Link in SRDB & MPLS LFIB */
UNSET_FLAG(exti->flags, EXT_LPFLG_FIB_ENTRY_SET);
ospf_sr_ext_itf_delete(exti);
}
/**
* Update Extended Link LSA once Segment Routing Label Block has been changed.
*/
void ospf_ext_link_srlb_update(void)
{
struct listnode *node;
struct ext_itf *exti;
osr_debug("EXT (%s): Update Extended Links with new SRLB", __func__);
/* Update all Extended Link Adjaceny-SID */
for (ALL_LIST_ELEMENTS_RO(OspfEXT.iflist, node, exti)) {
/* Skip Extended Prefix */
if (exti->stype == PREF_SID || exti->stype == LOCAL_SID)
continue;
/* Skip inactive Extended Link */
if (!CHECK_FLAG(exti->flags, EXT_LPFLG_LSA_ACTIVE))
continue;
ospf_ext_link_update_adj_sid(exti);
}
}
/*
* Used by Segment Routing to activate/deactivate Extended Link/Prefix flooding
*
@ -541,10 +649,15 @@ 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 */
/* Skip Inactive Extended Link */
if (!CHECK_FLAG(exti->flags, EXT_LPFLG_LSA_ACTIVE))
continue;
/* Update Extended Link (LAN)Adj-SID if not set */
if (!CHECK_FLAG(exti->flags, EXT_LPFLG_FIB_ENTRY_SET))
ospf_ext_link_update_adj_sid(exti);
/* Finally, flood the extended Link */
if (CHECK_FLAG(exti->flags, EXT_LPFLG_LSA_ENGAGED))
ospf_ext_lsa_schedule(exti, REFRESH_THIS_LSA);
else
@ -684,7 +797,6 @@ static void ospf_ext_link_nsm_change(struct ospf_neighbor *nbr, int old_status)
{
struct ospf_interface *oi = nbr->oi;
struct ext_itf *exti;
uint32_t label;
/* Process Link only when neighbor old or new state is NSM Full */
if (nbr->state != NSM_Full && old_status != NSM_Full)
@ -709,7 +821,10 @@ static void ospf_ext_link_nsm_change(struct ospf_neighbor *nbr, int old_status)
/* Remove Extended Link if Neighbor State goes Down or Deleted */
if (nbr->state == NSM_Down || nbr->state == NSM_Deleted) {
ospf_extended_lsa_delete(exti);
ospf_ext_link_delete_adj_sid(exti);
if (CHECK_FLAG(exti->flags, EXT_LPFLG_LSA_ENGAGED))
ospf_ext_link_lsa_schedule(exti, FLUSH_THIS_LSA);
exti->flags = EXT_LPFLG_LSA_INACTIVE;
return;
}
@ -729,11 +844,6 @@ static void ospf_ext_link_nsm_change(struct ospf_neighbor *nbr, int old_status)
set_ext_link(exti, OSPF_IFTYPE_POINTOPOINT, nbr->router_id,
oi->address->u.prefix4);
/* Set Extended Link Adjacency SubTLVs, backup first */
label = get_ext_link_label_value();
set_adj_sid(exti, true, label, SID_LABEL);
label = get_ext_link_label_value();
set_adj_sid(exti, false, label, SID_LABEL);
/* And Remote Interface address */
set_rmt_itf_addr(exti, nbr->address.u.prefix4);
@ -747,11 +857,9 @@ static void ospf_ext_link_nsm_change(struct ospf_neighbor *nbr, int old_status)
set_ext_link(exti, OSPF_IFTYPE_BROADCAST, DR(oi),
oi->address->u.prefix4);
/* Set Extended Link Adjacency SubTLVs, backup first */
label = get_ext_link_label_value();
set_lan_adj_sid(exti, true, label, SID_LABEL, nbr->router_id);
label = get_ext_link_label_value();
set_lan_adj_sid(exti, false, label, SID_LABEL, nbr->router_id);
/* Set Neighbor ID */
exti->lan_sid[0].neighbor_id = nbr->router_id;
exti->lan_sid[1].neighbor_id = nbr->router_id;
break;
@ -764,36 +872,33 @@ static void ospf_ext_link_nsm_change(struct ospf_neighbor *nbr, int old_status)
set_ext_link(exti, OSPF_IFTYPE_BROADCAST, DR(oi),
oi->address->u.prefix4);
/* Set Extended Link Adjacency SubTLVs, backup first */
label = get_ext_link_label_value();
set_adj_sid(exti, true, label, SID_LABEL);
label = get_ext_link_label_value();
set_adj_sid(exti, false, label, SID_LABEL);
break;
default:
if (CHECK_FLAG(exti->flags, EXT_LPFLG_FIB_ENTRY_SET))
ospf_ext_link_delete_adj_sid(exti);
if (CHECK_FLAG(exti->flags, EXT_LPFLG_LSA_ENGAGED))
ospf_ext_link_lsa_schedule(exti, FLUSH_THIS_LSA);
exti->flags = EXT_LPFLG_LSA_INACTIVE;
return;
}
osr_debug("EXT (%s): Complete %sAdjacency SID for interface %s ",
__func__, exti->stype == ADJ_SID ? "" : "LAN-",
oi->ifp->name);
/* flood this links params if everything is ok */
SET_FLAG(exti->flags, EXT_LPFLG_LSA_ACTIVE);
if (OspfEXT.enabled) {
osr_debug("EXT (%s): Set %sAdjacency SID for interface %s ",
__func__, exti->stype == ADJ_SID ? "" : "LAN-",
oi->ifp->name);
/* Update (LAN)Adjacency SID */
ospf_ext_link_update_adj_sid(exti);
/* flood this links params if everything is ok */
if (CHECK_FLAG(exti->flags, EXT_LPFLG_LSA_ENGAGED))
ospf_ext_link_lsa_schedule(exti, REFRESH_THIS_LSA);
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 */

View File

@ -189,6 +189,7 @@ extern int ospf_ext_init(void);
extern void ospf_ext_term(void);
extern void ospf_ext_finish(void);
extern void ospf_ext_update_sr(bool enable);
extern void ospf_ext_link_srlb_update(void);
extern uint32_t ospf_ext_schedule_prefix_index(struct interface *ifp,
uint32_t index,
struct prefix_ipv4 *p,

View File

@ -442,29 +442,52 @@ static void unset_sr_algorithm(uint8_t algo)
TLV_LEN(OspfRI.sr_info.algo) = htons(0);
}
/* Segment Routing Global Block SubTLV - section 3.2 */
static void set_sr_sid_label_range(struct sr_srgb srgb)
/* Set Segment Routing Global Block SubTLV - section 3.2 */
static void set_sr_global_label_range(struct sr_block srgb)
{
/* Set Header */
TLV_TYPE(OspfRI.sr_info.range) = htons(RI_SR_TLV_SID_LABEL_RANGE);
TLV_LEN(OspfRI.sr_info.range) =
TLV_TYPE(OspfRI.sr_info.srgb) = htons(RI_SR_TLV_SRGB_LABEL_RANGE);
TLV_LEN(OspfRI.sr_info.srgb) =
htons(SUBTLV_SID_LABEL_SIZE + sizeof(uint32_t));
/* Set Range Size */
OspfRI.sr_info.range.size = htonl(SET_RANGE_SIZE(srgb.range_size));
OspfRI.sr_info.srgb.size = htonl(SET_RANGE_SIZE(srgb.range_size));
/* Set Lower bound label SubTLV */
TLV_TYPE(OspfRI.sr_info.range.lower) = htons(SUBTLV_SID_LABEL);
TLV_LEN(OspfRI.sr_info.range.lower) = htons(SID_RANGE_LABEL_LENGTH);
OspfRI.sr_info.range.lower.value = htonl(SET_LABEL(srgb.lower_bound));
TLV_TYPE(OspfRI.sr_info.srgb.lower) = htons(SUBTLV_SID_LABEL);
TLV_LEN(OspfRI.sr_info.srgb.lower) = htons(SID_RANGE_LABEL_LENGTH);
OspfRI.sr_info.srgb.lower.value = htonl(SET_LABEL(srgb.lower_bound));
}
/* Unset this SRGB SubTLV */
static void unset_sr_sid_label_range(void)
/* Unset Segment Routing Global Block SubTLV */
static void unset_sr_global_label_range(void)
{
TLV_TYPE(OspfRI.sr_info.srgb) = htons(0);
TLV_LEN(OspfRI.sr_info.srgb) = htons(0);
TLV_TYPE(OspfRI.sr_info.srgb.lower) = htons(0);
TLV_LEN(OspfRI.sr_info.srgb.lower) = htons(0);
}
TLV_TYPE(OspfRI.sr_info.range) = htons(0);
TLV_LEN(OspfRI.sr_info.range) = htons(0);
TLV_TYPE(OspfRI.sr_info.range.lower) = htons(0);
TLV_LEN(OspfRI.sr_info.range.lower) = htons(0);
/* Set Segment Routing Local Block SubTLV - section 3.2 */
static void set_sr_local_label_range(struct sr_block srlb)
{
/* Set Header */
TLV_TYPE(OspfRI.sr_info.srlb) = htons(RI_SR_TLV_SRLB_LABEL_RANGE);
TLV_LEN(OspfRI.sr_info.srlb) =
htons(SUBTLV_SID_LABEL_SIZE + sizeof(uint32_t));
/* Set Range Size */
OspfRI.sr_info.srlb.size = htonl(SET_RANGE_SIZE(srlb.range_size));
/* Set Lower bound label SubTLV */
TLV_TYPE(OspfRI.sr_info.srlb.lower) = htons(SUBTLV_SID_LABEL);
TLV_LEN(OspfRI.sr_info.srlb.lower) = htons(SID_RANGE_LABEL_LENGTH);
OspfRI.sr_info.srlb.lower.value = htonl(SET_LABEL(srlb.lower_bound));
}
/* Unset Segment Routing Local Block SubTLV */
static void unset_sr_local_label_range(void)
{
TLV_TYPE(OspfRI.sr_info.srlb) = htons(0);
TLV_LEN(OspfRI.sr_info.srlb) = htons(0);
TLV_TYPE(OspfRI.sr_info.srlb.lower) = htons(0);
TLV_LEN(OspfRI.sr_info.srlb.lower) = htons(0);
}
/* Set Maximum Stack Depth for this router */
@ -563,7 +586,7 @@ static int is_mandated_params_set(struct ospf_router_info ori)
return rc;
if ((ori.sr_info.enabled) && (ntohs(TLV_TYPE(ori.sr_info.algo)) == 0)
&& (ntohs(TLV_TYPE(ori.sr_info.range)) == 0))
&& (ntohs(TLV_TYPE(ori.sr_info.srgb)) == 0))
return rc;
rc = 1;
@ -575,13 +598,11 @@ static int is_mandated_params_set(struct ospf_router_info ori)
* Used by Segment Routing to set new TLVs and Sub-TLVs values
*
* @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 supported by the router
* @param srn Self Segment Routing node
*
* @return none
*/
void ospf_router_info_update_sr(bool enable, struct sr_srgb srgb, uint8_t msd)
void ospf_router_info_update_sr(bool enable, struct sr_node *srn)
{
struct listnode *node, *nnode;
struct ospf_ri_area_info *ai;
@ -612,15 +633,17 @@ void ospf_router_info_update_sr(bool enable, struct sr_srgb srgb, uint8_t msd)
/* Unset or Set SR parameters */
if (!enable) {
unset_sr_algorithm(SR_ALGORITHM_SPF);
unset_sr_sid_label_range();
unset_sr_global_label_range();
unset_sr_local_label_range();
unset_sr_node_msd();
OspfRI.sr_info.enabled = false;
} else {
// Only SR_ALGORITHM_SPF is supported
set_sr_algorithm(SR_ALGORITHM_SPF);
set_sr_sid_label_range(srgb);
if (msd != 0)
set_sr_node_msd(msd);
set_sr_global_label_range(srn->srgb);
set_sr_local_label_range(srn->srlb);
if (srn->msd != 0)
set_sr_node_msd(srn->msd);
else
unset_sr_node_msd();
OspfRI.sr_info.enabled = true;
@ -698,7 +721,9 @@ static void ospf_router_info_lsa_body_set(struct stream *s)
/* Build Algorithm TLV */
build_tlv(s, &TLV_HDR(OspfRI.sr_info.algo));
/* Build SRGB TLV */
build_tlv(s, &TLV_HDR(OspfRI.sr_info.range));
build_tlv(s, &TLV_HDR(OspfRI.sr_info.srgb));
/* Build SRLB TLV */
build_tlv(s, &TLV_HDR(OspfRI.sr_info.srlb));
/* Build MSD TLV */
build_tlv(s, &TLV_HDR(OspfRI.sr_info.msd));
}
@ -1409,16 +1434,22 @@ static uint16_t show_vty_sr_range(struct vty *vty, struct tlv_header *tlvh)
if (vty != NULL) {
vty_out(vty,
" Segment Routing Range TLV:\n"
" Segment Routing %s Range TLV:\n"
" Range Size = %d\n"
" SID Label = %d\n\n",
ntohs(range->header.type) == RI_SR_TLV_SRGB_LABEL_RANGE
? "Global"
: "Local",
GET_RANGE_SIZE(ntohl(range->size)),
GET_LABEL(ntohl(range->lower.value)));
} else {
zlog_debug(
" Segment Routing Range TLV:\n"
" Segment Routing %s Range TLV:\n"
" Range Size = %d\n"
" SID Label = %d\n\n",
ntohs(range->header.type) == RI_SR_TLV_SRGB_LABEL_RANGE
? "Global"
: "Local",
GET_RANGE_SIZE(ntohl(range->size)),
GET_LABEL(ntohl(range->lower.value)));
}
@ -1469,7 +1500,8 @@ static void ospf_router_info_show_info(struct vty *vty, struct ospf_lsa *lsa)
case RI_SR_TLV_SR_ALGORITHM:
sum += show_vty_sr_algorithm(vty, tlvh);
break;
case RI_SR_TLV_SID_LABEL_RANGE:
case RI_SR_TLV_SRGB_LABEL_RANGE:
case RI_SR_TLV_SRLB_LABEL_RANGE:
sum += show_vty_sr_range(vty, tlvh);
break;
case RI_SR_TLV_NODE_MSD:

View File

@ -201,7 +201,12 @@ struct ospf_ri_sr_info {
* Segment Routing Global Block i.e. label range
* Only one range supported in this code
*/
struct ri_sr_tlv_sid_label_range range;
struct ri_sr_tlv_sid_label_range srgb;
/*
* Segment Routing Local Block.
* Only one block is authorized - see section 3.3
*/
struct ri_sr_tlv_sid_label_range srlb;
/* Maximum SID Depth supported by the node */
struct ri_sr_tlv_node_msd msd;
};
@ -242,7 +247,6 @@ extern int ospf_router_info_init(void);
extern void ospf_router_info_term(void);
extern void ospf_router_info_finish(void);
extern int ospf_router_info_enable(void);
extern void ospf_router_info_update_sr(bool enable, struct sr_srgb srgb,
uint8_t msd);
extern void ospf_router_info_update_sr(bool enable, struct sr_node *self);
extern struct scope_info ospf_router_info_get_flooding_scope(void);
#endif /* _ZEBRA_OSPF_ROUTER_INFO_H */

View File

@ -1,13 +1,14 @@
/*
* This is an implementation of Segment Routing
* as per draft draft-ietf-ospf-segment-routing-extensions-24
* as per RFC 8665 - OSPF Extensions for Segment Routing
* and RFC 8476 - Signaling Maximum SID Depth (MSD) Using OSPF
*
* Module name: Segment Routing
*
* Author: Olivier Dugeon <olivier.dugeon@orange.com>
* Author: Anselme Sawadogo <anselmesawadogo@gmail.com>
*
* Copyright (C) 2016 - 2018 Orange Labs http://www.orange.com
* Copyright (C) 2016 - 2020 Orange Labs http://www.orange.com
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
@ -218,6 +219,182 @@ static struct sr_node *get_sr_node_by_nexthop(struct ospf *ospf,
return srn;
}
/*
* Segment Routing Local Block management functions
*/
/**
* It is necessary to known which label is already allocated to manage the range
* of SRLB. This is particular useful when an interface flap (goes up / down
* frequently). Here, SR will release and then allocate label for the Adjacency
* for each concerned interface. If we don't care, there is a risk to run out of
* label.
*
* For that purpose, a similar principle as already provided to manage chunk of
* label is proposed. But, here, the label chunk has not a fix range of 64
* labels that could be easily manage with a single variable of 64 bits size.
* So, used_mark is used as a bit wise to mark label reserved (bit set) or not
* (bit unset). Its size is equal to the number of label of the SRLB range round
* up to 64 bits.
*
* - sr__local_block_init() computes the number of 64 bits variables that are
* needed to manage the SRLB range and allocates this number.
* - ospf_sr_local_block_request_label() pick up the first available label and
* set corresponding bit
* - ospf_sr_local_block_release_label() release label by reseting the
* corresponding bit and set the next label to the first free position
*/
/**
* Initialize Segment Routing Local Block from SRDB configuration and reserve
* block of bits to manage label allocation.
*
* @param lower_bound The lower bound of the SRLB range
* @param upper_bound The upper bound of the SRLB range
*
* @return 0 on success, -1 otherwise
*/
static int sr_local_block_init(uint32_t lower_bound, uint32_t upper_bound)
{
struct sr_local_block *srlb = &OspfSR.srlb;
uint32_t size;
/* Check if SRLB is not already configured */
if (srlb->reserved)
return 0;
/*
* Request SRLB to the label manager. If the allocation fails, return
* an error to disable SR until a new SRLB is successfully allocated.
*/
size = upper_bound - lower_bound + 1;
if (ospf_zebra_request_label_range(lower_bound, size)) {
srlb->reserved = false;
return -1;
}
osr_debug("SR (%s): Got new SRLB [%u/%u]", __func__, lower_bound,
upper_bound);
/* Initialize the SRLB */
srlb->start = lower_bound;
srlb->end = upper_bound;
srlb->current = 0;
/* Compute the needed Used Mark number and allocate them */
srlb->max_block = size / SRLB_BLOCK_SIZE;
if ((size % SRLB_BLOCK_SIZE) != 0)
srlb->max_block++;
srlb->used_mark = XCALLOC(MTYPE_OSPF_SR_PARAMS,
srlb->max_block * SRLB_BLOCK_SIZE);
srlb->reserved = true;
return 0;
}
/**
* Remove Segment Routing Local Block.
*
*/
static void sr_local_block_delete()
{
struct sr_local_block *srlb = &OspfSR.srlb;
/* Check if SRLB is not already delete */
if (!srlb->reserved)
return;
osr_debug("SR (%s): Remove SRLB [%u/%u]", __func__, srlb->start,
srlb->end);
/* First release the label block */
ospf_zebra_release_label_range(srlb->start, srlb->end);
/* Then reset SRLB structure */
if (srlb->used_mark != NULL)
XFREE(MTYPE_OSPF_SR_PARAMS, srlb->used_mark);
srlb->reserved = false;
}
/**
* Request a label from the Segment Routing Local Block.
*
* @return First available label on success or MPLS_INVALID_LABEL if the
* block of labels is full
*/
mpls_label_t ospf_sr_local_block_request_label(void)
{
struct sr_local_block *srlb = &OspfSR.srlb;
mpls_label_t label;
uint32_t index;
uint32_t pos;
/* Check if we ran out of available labels */
if (srlb->current >= srlb->end)
return MPLS_INVALID_LABEL;
/* Get first available label and mark it used */
label = srlb->current + srlb->start;
index = srlb->current / SRLB_BLOCK_SIZE;
pos = 1ULL << (srlb->current % SRLB_BLOCK_SIZE);
srlb->used_mark[index] |= pos;
/* Jump to the next free position */
srlb->current++;
pos = srlb->current % SRLB_BLOCK_SIZE;
while (srlb->current < srlb->end) {
if (pos == 0)
index++;
if (!((1ULL << pos) & srlb->used_mark[index]))
break;
else {
srlb->current++;
pos = srlb->current % SRLB_BLOCK_SIZE;
}
}
return label;
}
/**
* Release label in the Segment Routing Local Block.
*
* @param label Label to be release
*
* @return 0 on success or -1 if label falls outside SRLB
*/
int ospf_sr_local_block_release_label(mpls_label_t label)
{
struct sr_local_block *srlb = &OspfSR.srlb;
uint32_t index;
uint32_t pos;
/* Check that label falls inside the SRLB */
if ((label < srlb->start) || (label > srlb->end)) {
flog_warn(EC_OSPF_SR_SID_OVERFLOW,
"%s: Returning label %u is outside SRLB [%u/%u]",
__func__, label, srlb->start, srlb->end);
return -1;
}
index = (label - srlb->start) / SRLB_BLOCK_SIZE;
pos = 1ULL << ((label - srlb->start) % SRLB_BLOCK_SIZE);
srlb->used_mark[index] &= ~pos;
/* Reset current to the first available position */
for (index = 0; index < srlb->max_block; index++) {
if (srlb->used_mark[index] != 0xFFFFFFFFFFFFFFFF) {
for (pos = 0; pos < SRLB_BLOCK_SIZE; pos++)
if (!((1ULL << pos) & srlb->used_mark[index])) {
srlb->current =
index * SRLB_BLOCK_SIZE + pos;
break;
}
break;
}
}
return 0;
}
/*
* Segment Routing Initialization functions
*/
@ -258,8 +435,10 @@ static int ospf_sr_start(struct ospf *ospf)
(void *)sr_node_new);
/* Complete & Store self SR Node */
srn->srgb.range_size = OspfSR.srgb.range_size;
srn->srgb.lower_bound = OspfSR.srgb.lower_bound;
srn->srgb.range_size = OspfSR.srgb.size;
srn->srgb.lower_bound = OspfSR.srgb.start;
srn->srlb.lower_bound = OspfSR.srlb.start;
srn->srlb.range_size = OspfSR.srlb.end - OspfSR.srlb.start + 1;
srn->algo[0] = OspfSR.algo[0];
srn->msd = OspfSR.msd;
OspfSR.self = srn;
@ -276,18 +455,19 @@ static int ospf_sr_start(struct ospf *ospf)
}
/*
* Request SGRB to the label manager if not already active. If the
* allocation fails, return an error to disable SR until a new SRGB
* is successfully allocated.
* Request SRLB & SGRB to the label manager if not already reserved.
* If the allocation fails, return an error to disable SR until a new
* SRLB and/or SRGB are successfully allocated.
*/
if (!OspfSR.srgb_reserved) {
if (ospf_zebra_request_label_range(OspfSR.srgb.lower_bound,
OspfSR.srgb.range_size)
sr_local_block_init(OspfSR.srlb.start, OspfSR.srlb.end);
if (!OspfSR.srgb.reserved) {
if (ospf_zebra_request_label_range(OspfSR.srgb.start,
OspfSR.srgb.size)
< 0) {
OspfSR.srgb_reserved = false;
OspfSR.srgb.reserved = false;
return -1;
} else
OspfSR.srgb_reserved = true;
OspfSR.srgb.reserved = true;
}
/* SR is UP and ready to flood LSA */
@ -296,7 +476,7 @@ static int ospf_sr_start(struct ospf *ospf)
/* Set Router Information SR parameters */
osr_debug("SR: Activate SR for Router Information LSA");
ospf_router_info_update_sr(true, OspfSR.srgb, OspfSR.msd);
ospf_router_info_update_sr(true, OspfSR.self);
/* Update Ext LSA */
osr_debug("SR: Activate SR for Extended Link/Prefix LSA");
@ -341,13 +521,22 @@ static void ospf_sr_stop(void)
/* Disable any re-attempt to connect to Label Manager */
THREAD_TIMER_OFF(OspfSR.t_start_lm);
/* Release SRGB if active. */
if (OspfSR.srgb_reserved) {
/* Release SRGB & SRLB if active. */
if (OspfSR.srgb.reserved)
ospf_zebra_release_label_range(
OspfSR.srgb.lower_bound,
OspfSR.srgb.lower_bound + OspfSR.srgb.range_size - 1);
OspfSR.srgb_reserved = false;
}
OspfSR.srgb.start,
OspfSR.srgb.start + OspfSR.srgb.size - 1);
sr_local_block_delete();
/* Revert SRGB, SRLB and MSD to default values */
OspfSR.srgb.size = DEFAULT_SRGB_SIZE;
OspfSR.srgb.start = DEFAULT_SRGB_LABEL;
OspfSR.srgb.reserved = false;
OspfSR.srlb.start = DEFAULT_SRLB_LABEL;
OspfSR.srlb.end = DEFAULT_SRLB_LABEL + DEFAULT_SRLB_SIZE - 1;
OspfSR.srlb.reserved = false;
OspfSR.msd = 0;
/*
* Remove all SR Nodes from the Hash table. Prefix and Link SID will
@ -376,15 +565,19 @@ int ospf_sr_init(void)
/* Only AREA flooding is supported in this release */
OspfSR.scope = OSPF_OPAQUE_AREA_LSA;
/* Initialize SRGB, Algorithms and MSD TLVs */
/* Initialize Algorithms, SRGB, SRLB and MSD TLVs */
/* Only Algorithm SPF is supported */
OspfSR.algo[0] = SR_ALGORITHM_SPF;
for (int i = 1; i < ALGORITHM_COUNT; i++)
OspfSR.algo[i] = SR_ALGORITHM_UNSET;
OspfSR.srgb.range_size = MPLS_DEFAULT_MAX_SRGB_SIZE;
OspfSR.srgb.lower_bound = MPLS_DEFAULT_MIN_SRGB_LABEL;
OspfSR.srgb_reserved = false;
OspfSR.srgb.size = DEFAULT_SRGB_SIZE;
OspfSR.srgb.start = DEFAULT_SRGB_LABEL;
OspfSR.srgb.reserved = false;
OspfSR.srlb.start = DEFAULT_SRLB_LABEL;
OspfSR.srlb.end = DEFAULT_SRLB_LABEL + DEFAULT_SRLB_SIZE - 1;
OspfSR.srlb.reserved = false;
OspfSR.msd = 0;
/* Initialize Hash table for neighbor SR nodes */
@ -443,7 +636,7 @@ void ospf_sr_finish(void)
*/
/* Compute label from index */
static mpls_label_t index2label(uint32_t index, struct sr_srgb srgb)
static mpls_label_t index2label(uint32_t index, struct sr_block srgb)
{
mpls_label_t label;
@ -588,7 +781,7 @@ static int compute_prefix_nhlfe(struct sr_prefix *srp)
return rc;
/* Compute Input Label with self SRGB */
srp->label_in = index2label(srp->sid, OspfSR.srgb);
srp->label_in = index2label(srp->sid, OspfSR.self->srgb);
rc = 0;
for (ALL_LIST_ELEMENTS_RO(srp->route->paths, node, path)) {
@ -973,9 +1166,11 @@ static void update_in_nhlfe(struct hash_bucket *bucket, void *args)
if (CHECK_FLAG(srp->flags, EXT_SUBTLV_PREFIX_SID_VFLG))
continue;
/* OK. Compute new input label ... */
srp->label_in = index2label(srp->sid, OspfSR.srgb);
/* ... and update MPLS LFIB */
/* First, remove old MPLS table entries ... */
ospf_zebra_delete_prefix_sid(srp);
/* ... then compute new input label ... */
srp->label_in = index2label(srp->sid, OspfSR.self->srgb);
/* ... and install new MPLS LFIB */
ospf_zebra_update_prefix_sid(srp);
}
}
@ -1024,8 +1219,9 @@ void ospf_sr_ri_lsa_update(struct ospf_lsa *lsa)
struct tlv_header *tlvh;
struct lsa_header *lsah = lsa->data;
struct ri_sr_tlv_sid_label_range *ri_srgb = NULL;
struct ri_sr_tlv_sid_label_range *ri_srlb = NULL;
struct ri_sr_tlv_sr_algorithm *algo = NULL;
struct sr_srgb srgb;
struct sr_block srgb;
uint16_t length = 0, sum = 0;
uint8_t msd = 0;
@ -1061,10 +1257,14 @@ void ospf_sr_ri_lsa_update(struct ospf_lsa *lsa)
algo = (struct ri_sr_tlv_sr_algorithm *)tlvh;
sum += TLV_SIZE(tlvh);
break;
case RI_SR_TLV_SID_LABEL_RANGE:
case RI_SR_TLV_SRGB_LABEL_RANGE:
ri_srgb = (struct ri_sr_tlv_sid_label_range *)tlvh;
sum += TLV_SIZE(tlvh);
break;
case RI_SR_TLV_SRLB_LABEL_RANGE:
ri_srlb = (struct ri_sr_tlv_sid_label_range *)tlvh;
sum += TLV_SIZE(tlvh);
break;
case RI_SR_TLV_NODE_MSD:
msd = ((struct ri_sr_tlv_node_msd *)(tlvh))->value;
sum += TLV_SIZE(tlvh);
@ -1121,9 +1321,12 @@ void ospf_sr_ri_lsa_update(struct ospf_lsa *lsa)
}
/* update LSA ID */
srn->instance = ntohl(lsah->id.s_addr);
/* Copy SRGB */
srn->srgb.range_size = srgb.range_size;
srn->srgb.lower_bound = srgb.lower_bound;
}
/* Set Algorithm */
/* Update Algorithm, SRLB and MSD if present */
if (algo != NULL) {
int i;
for (i = 0; i < ntohs(algo->header.length); i++)
@ -1133,8 +1336,21 @@ void ospf_sr_ri_lsa_update(struct ospf_lsa *lsa)
} else {
srn->algo[0] = SR_ALGORITHM_SPF;
}
srn->msd = msd;
if (ri_srlb != NULL) {
srn->srlb.range_size = GET_RANGE_SIZE(ntohl(ri_srlb->size));
srn->srlb.lower_bound = GET_LABEL(ntohl(ri_srlb->lower.value));
}
osr_debug(" |- Update SR-Node[%pI4], SRGB[%u/%u], SRLB[%u/%u], Algo[%u], MSD[%u]",
&srn->adv_router, srn->srgb.lower_bound, srn->srgb.range_size,
srn->srlb.lower_bound, srn->srlb.range_size, srn->algo[0],
srn->msd);
/* Check if SRGB has changed */
if ((srn->srgb.range_size == srgb.range_size)
&& (srn->srgb.lower_bound == srgb.lower_bound))
return;
/* Copy SRGB */
srn->srgb.range_size = srgb.range_size;
@ -1526,18 +1742,6 @@ void ospf_sr_ext_prefix_lsa_delete(struct ospf_lsa *lsa)
}
}
/* Get Label for Extended Link SID */
/* TODO: To be replace by Zebra Label Manager */
uint32_t get_ext_link_label_value(void)
{
static uint32_t label = ADJ_SID_MIN - 1;
if (label < ADJ_SID_MAX)
label += 1;
return label;
}
/*
* Update Prefix SID. Call by ospf_ext_pref_ism_change to
* complete initial CLI command at startup.
@ -1684,17 +1888,23 @@ void ospf_sr_config_write_router(struct vty *vty)
{
struct listnode *node;
struct sr_prefix *srp;
uint32_t upper;
if (OspfSR.status != SR_OFF) {
if (OspfSR.status == SR_UP) {
vty_out(vty, " segment-routing on\n");
if ((OspfSR.srgb.lower_bound != MPLS_DEFAULT_MIN_SRGB_LABEL)
|| (OspfSR.srgb.range_size != MPLS_DEFAULT_MAX_SRGB_SIZE)) {
upper = OspfSR.srgb.start + OspfSR.srgb.size - 1;
if ((OspfSR.srgb.start != DEFAULT_SRGB_LABEL)
|| (OspfSR.srgb.size != DEFAULT_SRGB_SIZE))
vty_out(vty, " segment-routing global-block %u %u\n",
OspfSR.srgb.lower_bound,
OspfSR.srgb.lower_bound + OspfSR.srgb.range_size
- 1);
}
OspfSR.srgb.start, upper);
upper = DEFAULT_SRLB_LABEL + DEFAULT_SRLB_SIZE - 1;
if ((OspfSR.srlb.start != DEFAULT_SRLB_LABEL)
|| (OspfSR.srlb.end != upper))
vty_out(vty, " segment-routing local-block %u %u\n",
OspfSR.srlb.start, OspfSR.srlb.end);
if (OspfSR.msd != 0)
vty_out(vty, " segment-routing node-msd %u\n",
OspfSR.msd);
@ -1759,7 +1969,7 @@ DEFUN (no_ospf_sr_enable,
ospf_ext_update_sr(false);
/* then, disable Router Information SR parameters */
ospf_router_info_update_sr(false, OspfSR.srgb, OspfSR.msd);
ospf_router_info_update_sr(false, OspfSR.self);
/* Finally, stop Segment Routing */
ospf_sr_stop();
@ -1790,21 +2000,20 @@ static int update_srgb(uint32_t lower, uint32_t size)
{
/* Check if values have changed */
if ((OspfSR.srgb.range_size == size)
&& (OspfSR.srgb.lower_bound == lower))
if ((OspfSR.srgb.size == size) && (OspfSR.srgb.start == lower))
return 0;
/* Release old SRGB if active. */
if (OspfSR.srgb_reserved) {
if (OspfSR.srgb.reserved) {
ospf_zebra_release_label_range(
OspfSR.srgb.lower_bound,
OspfSR.srgb.lower_bound + OspfSR.srgb.range_size - 1);
OspfSR.srgb_reserved = false;
OspfSR.srgb.start,
OspfSR.srgb.start + OspfSR.srgb.size - 1);
OspfSR.srgb.reserved = false;
}
/* Set new SRGB values */
OspfSR.srgb.range_size = size;
OspfSR.srgb.lower_bound = lower;
OspfSR.srgb.size = size;
OspfSR.srgb.start = lower;
if (OspfSR.self != NULL) {
OspfSR.self->srgb.range_size = size;
OspfSR.self->srgb.lower_bound = lower;
@ -1818,15 +2027,19 @@ static int update_srgb(uint32_t lower, uint32_t size)
* Try to reserve the new block from the Label Manger. If the allocation
* fails, disable SR until a new SRGB is successfully allocated.
*/
if (ospf_zebra_request_label_range(OspfSR.srgb.lower_bound,
OspfSR.srgb.range_size) < 0) {
OspfSR.srgb_reserved = false;
if (ospf_zebra_request_label_range(OspfSR.srgb.start,
OspfSR.srgb.size) < 0) {
OspfSR.srgb.reserved = false;
ospf_sr_stop();
return -1;
}
} else
OspfSR.srgb.reserved = true;
osr_debug("SR(%s): Got new SRGB [%u/%u]", __func__, OspfSR.srgb.start,
OspfSR.srgb.start + OspfSR.srgb.size - 1);
/* SRGB is reserved, set Router Information parameters */
ospf_router_info_update_sr(true, OspfSR.srgb, OspfSR.msd);
ospf_router_info_update_sr(true, OspfSR.self);
/* and update NHLFE entries */
hash_iterate(OspfSR.neighbors,
@ -1836,8 +2049,8 @@ static int update_srgb(uint32_t lower, uint32_t size)
return 0;
}
DEFUN (sr_sid_label_range,
sr_sid_label_range_cmd,
DEFUN (sr_global_label_range,
sr_global_label_range_cmd,
"segment-routing global-block (16-1048575) (16-1048575)",
SR_STR
"Segment Routing Global Block label range\n"
@ -1858,32 +2071,158 @@ DEFUN (sr_sid_label_range,
upper = strtoul(argv[idx_up]->arg, NULL, 10);
size = upper - lower + 1;
/* Validate SRGB against SRLB */
if (!((upper < OspfSR.srlb.start) || (lower > OspfSR.srlb.end))) {
vty_out(vty,
"New SR Global Block (%u/%u) conflict with Local Block (%u/%u)\n",
lower, upper, OspfSR.srlb.end, OspfSR.srlb.start);
return CMD_WARNING_CONFIG_FAILED;
}
if (update_srgb(lower, size) < 0)
return CMD_WARNING_CONFIG_FAILED;
else
return CMD_SUCCESS;
}
DEFUN (no_sr_sid_label_range,
no_sr_sid_label_range_cmd,
"no segment-routing global-block [(0-1048575) (0-1048575)]",
DEFUN (no_sr_global_label_range,
no_sr_global_label_range_cmd,
"no segment-routing global-block [(16-1048575) (16-1048575)]",
NO_STR
SR_STR
"Segment Routing Global Block label range\n"
"Lower-bound range in decimal (0-1048575)\n"
"Upper-bound range in decimal (0-1048575)\n")
"Lower-bound range in decimal (16-1048575)\n"
"Upper-bound range in decimal (16-1048575)\n")
{
if (!ospf_sr_enabled(vty))
return CMD_WARNING_CONFIG_FAILED;
if (update_srgb(MPLS_DEFAULT_MIN_SRGB_SIZE,
MPLS_DEFAULT_MIN_SRGB_LABEL) < 0)
/* Validate SRGB against SRLB */
uint32_t upper = DEFAULT_SRGB_LABEL + DEFAULT_SRGB_SIZE - 1;
if (!((upper < OspfSR.srlb.start)
|| (DEFAULT_SRGB_LABEL > OspfSR.srlb.end))) {
vty_out(vty,
"New SR Global Block (%u/%u) conflict with Local Block (%u/%u)\n",
DEFAULT_SRGB_LABEL, upper, OspfSR.srlb.end,
OspfSR.srlb.start);
return CMD_WARNING_CONFIG_FAILED;
}
if (update_srgb(DEFAULT_SRGB_LABEL, DEFAULT_SRGB_SIZE) < 0)
return CMD_WARNING_CONFIG_FAILED;
else
return CMD_SUCCESS;
}
DEFUN (sr_local_label_range,
sr_local_label_range_cmd,
"segment-routing local-block (16-1048575) (16-1048575)",
SR_STR
"Segment Routing Local Block label range\n"
"Lower-bound range in decimal (16-1048575)\n"
"Upper-bound range in decimal (16-1048575)\n")
{
uint32_t upper;
uint32_t lower;
uint32_t srgb_upper;
int idx_low = 2;
int idx_up = 3;
if (!ospf_sr_enabled(vty))
return CMD_WARNING_CONFIG_FAILED;
/* Get lower and upper bound */
lower = strtoul(argv[idx_low]->arg, NULL, 10);
upper = strtoul(argv[idx_up]->arg, NULL, 10);
/* Check if values have changed */
if ((OspfSR.srlb.start == lower)
&& (OspfSR.srlb.end == upper))
return CMD_SUCCESS;
/* Validate SRLB against SRGB */
srgb_upper = OspfSR.srgb.start + OspfSR.srgb.size - 1;
if (!((upper < OspfSR.srgb.start) || (lower > srgb_upper))) {
vty_out(vty,
"New SR Local Block (%u/%u) conflict with Global Block (%u/%u)\n",
lower, upper, OspfSR.srgb.start, srgb_upper);
return CMD_WARNING_CONFIG_FAILED;
}
/* Remove old SRLB */
sr_local_block_delete();
/* Try to reserve the new block from the Label Manger. If the allocation
* fails, disable SR until a new SRLB is successfully allocated.
*/
if (sr_local_block_init(lower, upper) != 0) {
ospf_sr_stop();
return CMD_WARNING_CONFIG_FAILED;
}
/* SRLB is reserved, Update Self SR-Node and Router Information LSA */
OspfSR.self->srlb.lower_bound = lower;
OspfSR.self->srlb.range_size = upper - lower + 1;
ospf_router_info_update_sr(true, OspfSR.self);
/* and update (LAN)-Adjacency SID */
ospf_ext_link_srlb_update();
return CMD_SUCCESS;
}
DEFUN (no_sr_local_label_range,
no_sr_local_label_range_cmd,
"no segment-routing local-block [(16-1048575) (16-1048575)]",
NO_STR
SR_STR
"Segment Routing Local Block label range\n"
"Lower-bound range in decimal (16-1048575)\n"
"Upper-bound range in decimal (16-1048575)\n")
{
uint32_t upper;
uint32_t srgb_end;
if (!ospf_sr_enabled(vty))
return CMD_WARNING_CONFIG_FAILED;
/* First, remove old SRLB */
sr_local_block_delete();
/* Validate SRLB against SRGB */
srgb_end = OspfSR.srgb.start + OspfSR.srgb.size - 1;
upper = DEFAULT_SRLB_LABEL + DEFAULT_SRLB_SIZE - 1;
if (!((upper < OspfSR.srgb.start) || (DEFAULT_SRLB_LABEL > srgb_end))) {
vty_out(vty,
"New SR Local Block (%u/%u) conflict with Global Block (%u/%u)\n",
DEFAULT_SRLB_LABEL, upper, OspfSR.srgb.start, srgb_end);
return CMD_WARNING_CONFIG_FAILED;
}
/* Then, initialize SRLB with default value and try to reserve the new
* block from the Label Manger. If the allocation fails, disable SR
* until a new SRLB is successfully allocated.
*/
if (sr_local_block_init(DEFAULT_SRLB_LABEL, upper) != 0) {
ospf_sr_stop();
return CMD_WARNING_CONFIG_FAILED;
}
/* SRLB is reserved, Update Self SR-Node and Router Information LSA */
if (OspfSR.self != NULL) {
OspfSR.self->srlb.lower_bound = DEFAULT_SRLB_LABEL;
OspfSR.self->srlb.range_size = DEFAULT_SRLB_SIZE;
}
ospf_router_info_update_sr(true, OspfSR.self);
/* and update (LAN)-Adjacency SID */
ospf_ext_link_srlb_update();
return CMD_SUCCESS;
}
DEFUN (sr_node_msd,
sr_node_msd_cmd,
"segment-routing node-msd (1-16)",
@ -1917,7 +2256,7 @@ DEFUN (sr_node_msd,
/* Set Router Information parameters if SR is UP */
if (OspfSR.status == SR_UP)
ospf_router_info_update_sr(true, OspfSR.srgb, OspfSR.msd);
ospf_router_info_update_sr(true, OspfSR.self);
return CMD_SUCCESS;
}
@ -1941,7 +2280,7 @@ DEFUN (no_sr_node_msd,
/* Set Router Information parameters if SR is UP */
if (OspfSR.status == SR_UP)
ospf_router_info_update_sr(true, OspfSR.srgb, 0);
ospf_router_info_update_sr(true, OspfSR.self);
return CMD_SUCCESS;
}
@ -1976,9 +2315,9 @@ DEFUN (sr_prefix_sid,
/* Get & verify index value */
argv_find(argv, argc, "(0-65535)", &idx);
index = strtoul(argv[idx]->arg, NULL, 10);
if (index > OspfSR.srgb.range_size - 1) {
if (index > OspfSR.srgb.size - 1) {
vty_out(vty, "Index %u must be lower than range size %u\n",
index, OspfSR.srgb.range_size);
index, OspfSR.srgb.size);
return CMD_WARNING_CONFIG_FAILED;
}
@ -2263,6 +2602,7 @@ static void show_sr_node(struct vty *vty, struct json_object *json,
char pref[19];
char sid[22];
char op[32];
uint32_t upper;
json_object *json_node = NULL, *json_algo, *json_obj;
json_object *json_prefix = NULL, *json_link = NULL;
@ -2280,6 +2620,10 @@ static void show_sr_node(struct vty *vty, struct json_object *json,
srn->srgb.range_size);
json_object_int_add(json_node, "srgbLabel",
srn->srgb.lower_bound);
json_object_int_add(json_node, "srlbSize",
srn->srlb.range_size);
json_object_int_add(json_node, "srlbLabel",
srn->srlb.lower_bound);
json_algo = json_object_new_array();
json_object_object_add(json_node, "algorithms", json_algo);
for (int i = 0; i < ALGORITHM_COUNT; i++) {
@ -2299,9 +2643,13 @@ static void show_sr_node(struct vty *vty, struct json_object *json,
json_object_int_add(json_node, "nodeMsd", srn->msd);
} else {
sbuf_push(&sbuf, 0, "SR-Node: %s", inet_ntoa(srn->adv_router));
sbuf_push(&sbuf, 0, "\tSRGB (Size/Label): %u/%u",
srn->srgb.range_size, srn->srgb.lower_bound);
sbuf_push(&sbuf, 0, "\tAlgorithm(s): %s",
upper = srn->srgb.lower_bound + srn->srgb.range_size - 1;
sbuf_push(&sbuf, 0, "\tSRGB: [%u/%u]",
srn->srgb.lower_bound, upper);
upper = srn->srlb.lower_bound + srn->srlb.range_size - 1;
sbuf_push(&sbuf, 0, "\tSRLB: [%u/%u]",
srn->srlb.lower_bound, upper);
sbuf_push(&sbuf, 0, "\tAlgo.(s): %s",
srn->algo[0] == SR_ALGORITHM_SPF ? "SPF" : "S-SPF");
for (int i = 1; i < ALGORITHM_COUNT; i++) {
if (srn->algo[i] == SR_ALGORITHM_UNSET)
@ -2505,8 +2853,10 @@ void ospf_sr_register_vty(void)
install_element(OSPF_NODE, &ospf_sr_enable_cmd);
install_element(OSPF_NODE, &no_ospf_sr_enable_cmd);
install_element(OSPF_NODE, &sr_sid_label_range_cmd);
install_element(OSPF_NODE, &no_sr_sid_label_range_cmd);
install_element(OSPF_NODE, &sr_global_label_range_cmd);
install_element(OSPF_NODE, &no_sr_global_label_range_cmd);
install_element(OSPF_NODE, &sr_local_label_range_cmd);
install_element(OSPF_NODE, &no_sr_local_label_range_cmd);
install_element(OSPF_NODE, &sr_node_msd_cmd);
install_element(OSPF_NODE, &no_sr_node_msd_cmd);
install_element(OSPF_NODE, &sr_prefix_sid_cmd);

View File

@ -1,13 +1,14 @@
/*
* This is an implementation of Segment Routing
* as per draft draft-ietf-ospf-segment-routing-extensions-24
* as per RFC 8665 - OSPF Extensions for Segment Routing
* and RFC 8476 - Signaling Maximum SID Depth (MSD) Using OSPF
*
* Module name: Segment Routing header definitions
*
* Author: Olivier Dugeon <olivier.dugeon@orange.com>
* Author: Anselme Sawadogo <anselmesawadogo@gmail.com>
*
* Copyright (C) 2016 - 2018 Orange Labs http://www.orange.com
* Copyright (C) 2016 - 2020 Orange Labs http://www.orange.com
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
@ -37,13 +38,9 @@
#define SET_LABEL(label) ((label << 8) & SET_LABEL_MASK)
#define GET_LABEL(label) ((label >> 8) & GET_LABEL_MASK)
/* Label range for Adj-SID attribution purpose. Start just right after SRGB */
#define ADJ_SID_MIN MPLS_DEFAULT_MAX_SRGB_LABEL
#define ADJ_SID_MAX (MPLS_DEFAULT_MAX_SRGB_LABEL + 1000)
#define OSPF_SR_DEFAULT_METRIC 1
/* Segment Routing TLVs as per draft-ietf-ospf-segment-routing-extensions-19 */
/* Segment Routing TLVs as per RFC 8665 */
/* Segment ID could be a Label (3 bytes) or an Index (4 bytes) */
#define SID_LABEL 3
@ -88,8 +85,9 @@ struct ri_sr_tlv_sr_algorithm {
uint8_t value[ALGORITHM_COUNT];
};
/* RI SID/Label Range TLV - section 3.2 */
#define RI_SR_TLV_SID_LABEL_RANGE 9
/* RI SID/Label Range TLV used for SRGB & SRLB - section 3.2 & 3.3 */
#define RI_SR_TLV_SRGB_LABEL_RANGE 9
#define RI_SR_TLV_SRLB_LABEL_RANGE 14
struct ri_sr_tlv_sid_label_range {
struct tlv_header header;
/* Only 24 upper most bits are significant */
@ -99,7 +97,7 @@ struct ri_sr_tlv_sid_label_range {
struct subtlv_sid_label lower;
};
/* RI Node/MSD TLV as per draft-ietf-ospf-segment-routing-msd-05 */
/* RI Node/MSD TLV as per RFC 8476 */
#define RI_SR_TLV_NODE_MSD 12
struct ri_sr_tlv_node_msd {
struct tlv_header header;
@ -183,13 +181,38 @@ struct ext_subtlv_lan_adj_sid {
* Following section define structure used to manage Segment Routing
* information and TLVs / SubTLVs
*/
/* Default min and size of SR Global Block label range */
#define DEFAULT_SRGB_LABEL 16000
#define DEFAULT_SRGB_SIZE 8000
/* Structure aggregating SRGB info retrieved from an lsa */
struct sr_srgb {
/* Default min and size of SR Local Block label range */
#define DEFAULT_SRLB_LABEL 15000
#define DEFAULT_SRLB_SIZE 1000
/* Structure aggregating SR Range Block info retrieved from an lsa */
struct sr_block {
uint32_t range_size;
uint32_t lower_bound;
};
/* Segment Routing Global Block allocation */
struct sr_global_block {
bool reserved;
uint32_t start;
uint32_t size;
};
/* Segment Routing Local Block allocation */
struct sr_local_block {
bool reserved;
uint32_t start;
uint32_t end;
uint32_t current;
uint32_t max_block;
uint64_t *used_mark;
};
#define SRLB_BLOCK_SIZE 64
/* SID type to make difference between loopback interfaces and others */
enum sid_type { PREF_SID, LOCAL_SID, ADJ_SID, LAN_ADJ_SID };
@ -221,16 +244,16 @@ struct ospf_sr_db {
* Segment Routing Global Block i.e. label range
* Only one range supported in this code
*/
struct sr_srgb srgb;
struct sr_global_block srgb;
/* Thread timer to start Label Manager */
struct thread *t_start_lm;
/* Status of SRGB: reserved within Label Manager or not */
bool srgb_reserved;
/* Segment Routing Local Block */
struct sr_local_block srlb;
/* Maximum SID Depth supported by the node */
uint8_t msd;
/* Thread timer to start Label Manager */
struct thread *t_start_lm;
};
/* Structure aggregating all received SR info from LSAs by node */
@ -240,9 +263,9 @@ struct sr_node {
uint32_t instance;
uint8_t algo[ALGORITHM_COUNT]; /* Algorithms supported by the node */
/* Segment Routing Global Block i.e. label range */
struct sr_srgb srgb;
uint8_t msd; /* Maximum SID Depth */
struct sr_block srgb; /* Segment Routing Global Block */
struct sr_block srlb; /* Segment Routing Local Block */
uint8_t msd; /* Maximum SID Depth */
/* List of Prefix & Link advertise by this node */
struct list *ext_prefix; /* For Node SID */
@ -252,7 +275,6 @@ struct sr_node {
struct sr_node *neighbor;
};
/* Segment Routing - NHLFE info: support IPv4 Only */
struct sr_nhlfe {
struct in_addr nexthop;
@ -319,6 +341,9 @@ struct sr_prefix {
extern int ospf_sr_init(void);
extern void ospf_sr_term(void);
extern void ospf_sr_finish(void);
/* Segment Routing label allocation functions */
extern mpls_label_t ospf_sr_local_block_request_label(void);
extern int ospf_sr_local_block_release_label(mpls_label_t label);
/* Segment Routing LSA update & delete functions */
extern void ospf_sr_ri_lsa_update(struct ospf_lsa *lsa);
extern void ospf_sr_ri_lsa_delete(struct ospf_lsa *lsa);
@ -331,7 +356,6 @@ 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);
extern void ospf_sr_update_local_prefix(struct interface *ifp,
struct prefix *p);

View File

@ -3,8 +3,10 @@
"srNodes":[
{
"routerID":"10.0.255.2",
"srgbSize":20000,
"srgbLabel":8000,
"srgbSize":8000,
"srgbLabel":16000,
"srlbSize":1000,
"srlbLabel":15000,
"algorithms":[
{
"0":"SPF"
@ -34,6 +36,8 @@
"routerID":"10.0.255.4",
"srgbSize":10000,
"srgbLabel":10000,
"srlbSize":1000,
"srlbLabel":5000,
"algorithms":[
{
"0":"SPF"
@ -47,12 +51,12 @@
"inputLabel":20400,
"prefixRoute":[
{
"outputLabel":8400,
"outputLabel":16400,
"interface":"r1-eth0",
"nexthop":"10.0.0.2"
},
{
"outputLabel":8400,
"outputLabel":16400,
"interface":"r1-eth1",
"nexthop":"10.0.1.2"
}
@ -64,8 +68,14 @@
"routerID":"10.0.255.3",
"srgbSize":10000,
"srgbLabel":10000,
"srlbSize":1000,
"srlbLabel":5000,
"algorithms":[
{
"0":"SPF"
}
],
"nodeMsd":8,
"extendedPrefix":[
{
"prefix":"10.0.255.3\/32",
@ -73,12 +83,12 @@
"inputLabel":20300,
"prefixRoute":[
{
"outputLabel":8300,
"outputLabel":16300,
"interface":"r1-eth0",
"nexthop":"10.0.0.2"
},
{
"outputLabel":8300,
"outputLabel":16300,
"interface":"r1-eth1",
"nexthop":"10.0.1.2"
}
@ -90,6 +100,8 @@
"routerID":"10.0.255.1",
"srgbSize":10000,
"srgbLabel":20000,
"srlbSize":1000,
"srlbLabel":15000,
"algorithms":[
{
"0":"SPF"

View File

@ -1,3 +1,4 @@
debug ospf sr
!
interface lo
ip ospf area 0.0.0.0

View File

@ -53,7 +53,7 @@
},
{
"type":"SR (OSPF)",
"outLabel":8300,
"outLabel":16300,
"distance":150,
"installed":true,
"nexthop":"10.0.0.2"
@ -76,7 +76,7 @@
},
{
"type":"SR (OSPF)",
"outLabel":8400,
"outLabel":16400,
"distance":150,
"installed":true,
"nexthop":"10.0.0.2"

View File

@ -3,8 +3,10 @@
"srNodes":[
{
"routerID":"10.0.255.2",
"srgbSize":20000,
"srgbLabel":8000,
"srgbSize":8000,
"srgbLabel":16000,
"srlbSize":1000,
"srlbLabel":15000,
"algorithms":[
{
"0":"SPF"
@ -95,13 +97,19 @@
"routerID":"10.0.255.4",
"srgbSize":10000,
"srgbLabel":10000,
"srlbSize":1000,
"srlbLabel":5000,
"algorithms":[
{
"0":"SPF"
}
],
"nodeMsd":12,
"extendedPrefix":[
{
"prefix":"10.0.255.4\/32",
"sid":400,
"inputLabel":8400,
"inputLabel":16400,
"prefixRoute":[
{
"outputLabel":10400,
@ -116,13 +124,19 @@
"routerID":"10.0.255.3",
"srgbSize":10000,
"srgbLabel":10000,
"srlbSize":1000,
"srlbLabel":5000,
"algorithms":[
{
"0":"SPF"
}
],
"nodeMsd":8,
"extendedPrefix":[
{
"prefix":"10.0.255.3\/32",
"sid":300,
"inputLabel":8300,
"inputLabel":16300,
"prefixRoute":[
{
"outputLabel":3,
@ -137,13 +151,19 @@
"routerID":"10.0.255.1",
"srgbSize":10000,
"srgbLabel":20000,
"srlbSize":1000,
"srlbLabel":15000,
"algorithms":[
{
"0":"SPF"
}
],
"nodeMsd":16,
"extendedPrefix":[
{
"prefix":"10.0.255.1\/32",
"sid":100,
"inputLabel":8100,
"inputLabel":16100,
"prefixRoute":[
{
"outputLabel":20100,

View File

@ -1,6 +1,6 @@
[
{
"inLabel":8100,
"inLabel":16100,
"installed":true,
"nexthops":[
{
@ -23,7 +23,7 @@
]
},
{
"inLabel":8300,
"inLabel":16300,
"installed":true,
"nexthops":[
{
@ -39,7 +39,7 @@
]
},
{
"inLabel":8400,
"inLabel":16400,
"installed":true,
"nexthops":[
{

View File

@ -3,8 +3,10 @@
"srNodes":[
{
"routerID":"10.0.255.2",
"srgbSize":20000,
"srgbLabel":8000,
"srgbSize":8000,
"srgbLabel":16000,
"srlbSize":1000,
"srlbLabel":15000,
"algorithms":[
{
"0":"SPF"
@ -29,6 +31,8 @@
"routerID":"10.0.255.4",
"srgbSize":10000,
"srgbLabel":10000,
"srlbSize":1000,
"srlbLabel":5000,
"algorithms":[
{
"0":"SPF"
@ -42,7 +46,7 @@
"inputLabel":10400,
"prefixRoute":[
{
"outputLabel":8400,
"outputLabel":16400,
"interface":"r3-eth0",
"nexthop":"10.0.3.2"
}
@ -54,6 +58,8 @@
"routerID":"10.0.255.3",
"srgbSize":10000,
"srgbLabel":10000,
"srlbSize":1000,
"srlbLabel":5000,
"algorithms":[
{
"0":"SPF"
@ -97,6 +103,8 @@
"routerID":"10.0.255.1",
"srgbSize":10000,
"srgbLabel":20000,
"srlbSize":1000,
"srlbLabel":15000,
"algorithms":[
{
"0":"SPF"
@ -110,7 +118,7 @@
"inputLabel":10100,
"prefixRoute":[
{
"outputLabel":8100,
"outputLabel":16100,
"interface":"r3-eth0",
"nexthop":"10.0.3.2"
}

View File

@ -11,6 +11,7 @@ router ospf
capability opaque
router-info area 0.0.0.0
segment-routing on
segment-routing local-block 5000 5999
segment-routing global-block 10000 19999
segment-routing node-msd 8
segment-routing prefix 10.0.255.3/32 index 300

View File

@ -3,9 +3,14 @@
"srNodes":[
{
"routerID":"10.0.255.2",
"srgbSize":20000,
"srgbLabel":8000,
"srgbSize":8000,
"srgbLabel":16000,
"srlbSize":1000,
"srlbLabel":15000,
"algorithms":[
{
"0":"SPF"
}
],
"extendedPrefix":[
{
@ -26,6 +31,8 @@
"routerID":"10.0.255.4",
"srgbSize":10000,
"srgbLabel":10000,
"srlbSize":1000,
"srlbLabel":5000,
"algorithms":[
{
"0":"SPF"
@ -69,8 +76,14 @@
"routerID":"10.0.255.3",
"srgbSize":10000,
"srgbLabel":10000,
"srlbSize":1000,
"srlbLabel":5000,
"algorithms":[
{
"0":"SPF"
}
],
"nodeMsd":8,
"extendedPrefix":[
{
"prefix":"10.0.255.3\/32",
@ -78,7 +91,7 @@
"inputLabel":10300,
"prefixRoute":[
{
"outputLabel":8300,
"outputLabel":16300,
"interface":"r4-eth0",
"nexthop":"10.0.4.2"
}
@ -90,8 +103,14 @@
"routerID":"10.0.255.1",
"srgbSize":10000,
"srgbLabel":20000,
"srlbSize":1000,
"srlbLabel":15000,
"algorithms":[
{
"0":"SPF"
}
],
"nodeMsd":16,
"extendedPrefix":[
{
"prefix":"10.0.255.1\/32",
@ -99,7 +118,7 @@
"inputLabel":10100,
"prefixRoute":[
{
"outputLabel":8100,
"outputLabel":16100,
"interface":"r4-eth0",
"nexthop":"10.0.4.2"
}

View File

@ -12,6 +12,7 @@ router ospf
capability opaque
router-info area 0.0.0.0
segment-routing on
segment-routing local-block 5000 5999
segment-routing global-block 10000 19999
segment-routing node-msd 12
segment-routing prefix 10.0.255.4/32 index 400 no-php-flag