OSPFd: Explicit Null option for Segment-Routing

Add new option to `segment-routing prefix` command to set the
Explcit Null flag in addition to the No-PHP flag. MPLS LFIB configuration
has been also updated to take into account the Explicit Null flag.

Signed-off-by: Olivier Dugeon <olivier.dugeon@orange.com>
This commit is contained in:
Olivier Dugeon 2020-07-08 20:12:19 +02:00
parent 6f751f1493
commit f786c4d7c9
9 changed files with 135 additions and 116 deletions

View File

@ -1099,13 +1099,15 @@ dataplane.
Fix the Maximum Stack Depth supported by the router. The value depend of the
MPLS dataplane. E.g. for Linux kernel, since version 4.13 it is 32.
.. index:: [no] segment-routing prefix A.B.C.D/M index (0-65535) [no-php-flag]
.. clicmd:: [no] segment-routing prefix A.B.C.D/M index (0-65535) [no-php-flag]
.. index:: [no] segment-routing prefix A.B.C.D/M index (0-65535) [no-php-flag|explicit-null]
.. clicmd:: [no] segment-routing prefix A.B.C.D/M [index (0-65535)|no-php-flag|explicit-null]
Set the Segment Routing index for the specified prefix. Note that, only
prefix with /32 corresponding to a loopback interface are currently
supported. The 'no-php-flag' means NO Penultimate Hop Popping that allows SR
node to request to its neighbor to not pop the label.
node to request to its neighbor to not pop the label. The 'explicit-null' means that
neighbor nodes must swap the incoming label by the MPLS Explicit Null label
before delivering the packet.
.. index:: show ip ospf database segment-routing <adv-router ADVROUTER|self-originate> [json]
.. clicmd:: show ip ospf database segment-routing <adv-router ADVROUTER|self-originate> [json]

View File

@ -641,9 +641,12 @@ static mpls_label_t index2label(uint32_t index, struct sr_block srgb)
mpls_label_t label;
label = srgb.lower_bound + index;
if (label > (srgb.lower_bound + srgb.range_size))
if (label > (srgb.lower_bound + srgb.range_size)) {
flog_warn(EC_OSPF_SR_SID_OVERFLOW,
"%s: SID index %u falls outside SRGB range",
__func__, index);
return MPLS_INVALID_LABEL;
else
} else
return label;
}
@ -750,6 +753,45 @@ static int compute_link_nhlfe(struct sr_link *srl)
return rc;
}
/**
* Compute output label for the given Prefix-SID.
*
* @param srp Segment Routing Prefix
* @param srnext Segment Routing nexthop node
*
* @return MPLS label or MPLS_INVALID_LABEL in case of error
*/
static mpls_label_t sr_prefix_out_label(const struct sr_prefix *srp,
const struct sr_node *srnext)
{
/* Check if the nexthop SR Node is the last hop? */
if (srnext == srp->srn) {
/* SR-Node doesn't request NO-PHP. Return Implicit NULL label */
if (!CHECK_FLAG(srp->flags, EXT_SUBTLV_PREFIX_SID_NPFLG))
return MPLS_LABEL_IMPLICIT_NULL;
/* SR-Node requests Explicit NULL Label */
if (CHECK_FLAG(srp->flags, EXT_SUBTLV_PREFIX_SID_EFLG))
return MPLS_LABEL_IPV4_EXPLICIT_NULL;
/* Fallthrough */
}
/* Return SID value as MPLS label if it is an Absolute SID */
if (CHECK_FLAG(srp->flags, EXT_SUBTLV_PREFIX_SID_VFLG
| EXT_SUBTLV_PREFIX_SID_LFLG)) {
/*
* V/L SIDs have local significance, so only adjacent routers
* can use them (RFC8665 section #5)
*/
if (srp->srn != srnext)
return MPLS_INVALID_LABEL;
return srp->sid;
}
/* Return MPLS label as SRGB lower bound + SID index as per RFC 8665 */
return (index2label(srp->sid, srnext->srgb));
}
/*
* Compute NHLFE entry for Extended Prefix
*
@ -800,10 +842,7 @@ static int compute_prefix_nhlfe(struct sr_prefix *srp)
/* And store this information for later update */
srnext->neighbor = OspfSR.self;
if (IPV4_ADDR_SAME(&srnext->adv_router, &srp->adv_router))
path->srni.nexthop = NULL;
else
path->srni.nexthop = srnext;
path->srni.nexthop = srnext;
/*
* SR Node could be known, but SRGB could be not initialize
@ -818,18 +857,8 @@ static int compute_prefix_nhlfe(struct sr_prefix *srp)
srnext->srgb.range_size, srnext->srgb.lower_bound,
&srnext->adv_router);
/*
* Compute Output Label with Nexthop SR Node SRGB or Implicit
* Null label if next hop is the destination and request PHP
*/
if ((path->srni.nexthop == NULL)
&& (!CHECK_FLAG(srp->flags, EXT_SUBTLV_PREFIX_SID_NPFLG)))
path->srni.label_out = MPLS_LABEL_IMPLICIT_NULL;
else if (CHECK_FLAG(srp->flags, EXT_SUBTLV_PREFIX_SID_VFLG))
path->srni.label_out = srp->sid;
else
path->srni.label_out =
index2label(srp->sid, srnext->srgb);
/* Compute Output Label with Nexthop SR Node SRGB */
path->srni.label_out = sr_prefix_out_label(srp, srnext);
osr_debug(" |- Computed new labels in: %u out: %u",
srp->label_in, path->srni.label_out);
@ -1194,7 +1223,7 @@ static void update_out_nhlfe(struct hash_bucket *bucket, void *args)
for (ALL_LIST_ELEMENTS_RO(srp->route->paths, pnode, path)) {
/* Process only SID Index for next hop without PHP */
if ((path->srni.nexthop == NULL)
if ((path->srni.nexthop == srp->srn)
&& (!CHECK_FLAG(srp->flags,
EXT_SUBTLV_PREFIX_SID_NPFLG)))
continue;
@ -1784,9 +1813,10 @@ void ospf_sr_update_local_prefix(struct interface *ifp, struct prefix *p)
" |- Update Node SID %pFX - %u for self SR Node",
(struct prefix *)&srp->prefv4, srp->sid);
/* Install NHLFE if NO-PHP is requested */
if (CHECK_FLAG(srp->flags,
EXT_SUBTLV_PREFIX_SID_NPFLG)) {
/* Install SID if NO-PHP is set and not EXPLICIT-NULL */
if (CHECK_FLAG(srp->flags, EXT_SUBTLV_PREFIX_SID_NPFLG)
&& !CHECK_FLAG(srp->flags,
EXT_SUBTLV_PREFIX_SID_EFLG)) {
srp->label_in = index2label(srp->sid,
OspfSR.self->srgb);
srp->nhlfe.label_out = MPLS_LABEL_IMPLICIT_NULL;
@ -1913,13 +1943,19 @@ void ospf_sr_config_write_router(struct vty *vty)
for (ALL_LIST_ELEMENTS_RO(OspfSR.self->ext_prefix, node,
srp)) {
vty_out(vty,
" segment-routing prefix %s/%u index %u%s\n",
" segment-routing prefix %s/%u "
"index %u",
inet_ntoa(srp->prefv4.prefix),
srp->prefv4.prefixlen, srp->sid,
CHECK_FLAG(srp->flags,
EXT_SUBTLV_PREFIX_SID_NPFLG)
? " no-php-flag"
: "");
srp->prefv4.prefixlen, srp->sid);
if (CHECK_FLAG(srp->flags,
EXT_SUBTLV_PREFIX_SID_EFLG))
vty_out(vty, " explicit-null\n");
else if (CHECK_FLAG(
srp->flags,
EXT_SUBTLV_PREFIX_SID_NPFLG))
vty_out(vty, " no-php-flag\n");
else
vty_out(vty, "\n");
}
}
}
@ -2287,19 +2323,20 @@ DEFUN (no_sr_node_msd,
DEFUN (sr_prefix_sid,
sr_prefix_sid_cmd,
"segment-routing prefix A.B.C.D/M index (0-65535) [no-php-flag]",
"segment-routing prefix A.B.C.D/M index (0-65535) [no-php-flag|explicit-null]",
SR_STR
"Prefix SID\n"
"IPv4 Prefix as A.B.C.D/M\n"
"SID index for this prefix in decimal (0-65535)\n"
"Index value inside SRGB (lower_bound < index < upper_bound)\n"
"Don't request Penultimate Hop Popping (PHP)\n")
"Don't request Penultimate Hop Popping (PHP)\n"
"Upstream neighbor must replace prefix-sid with explicit null label\n")
{
int idx = 0;
struct prefix p;
uint32_t index;
struct listnode *node;
struct sr_prefix *srp, *new;
struct sr_prefix *srp, *new = NULL;
struct interface *ifp;
if (!ospf_sr_enabled(vty))
@ -2321,27 +2358,42 @@ DEFUN (sr_prefix_sid,
return CMD_WARNING_CONFIG_FAILED;
}
/* check that the index is not already used */
/* Search for an existing Prefix-SID */
for (ALL_LIST_ELEMENTS_RO(OspfSR.self->ext_prefix, node, srp)) {
if (srp->sid == index) {
vty_out(vty, "Index %u is already used\n", index);
return CMD_WARNING_CONFIG_FAILED;
if (prefix_same((struct prefix *)&srp->prefv4, &p)) {
new = srp;
break;
} else {
vty_out(vty, "Index %u is already used\n",
index);
return CMD_WARNING_CONFIG_FAILED;
}
}
}
/* Create new Extended Prefix to SRDB if not found */
new = XCALLOC(MTYPE_OSPF_SR_PARAMS, sizeof(struct sr_prefix));
IPV4_ADDR_COPY(&new->prefv4.prefix, &p.u.prefix4);
new->prefv4.prefixlen = p.prefixlen;
new->prefv4.family = p.family;
new->sid = index;
new->type = LOCAL_SID;
if (new == NULL) {
new = XCALLOC(MTYPE_OSPF_SR_PARAMS, sizeof(struct sr_prefix));
IPV4_ADDR_COPY(&new->prefv4.prefix, &p.u.prefix4);
new->prefv4.prefixlen = p.prefixlen;
new->prefv4.family = p.family;
new->sid = index;
new->type = LOCAL_SID;
}
/* Set NO PHP flag if present and compute NHLFE */
if (argv_find(argv, argc, "no-php-flag", &idx)) {
SET_FLAG(new->flags, EXT_SUBTLV_PREFIX_SID_NPFLG);
UNSET_FLAG(new->flags, EXT_SUBTLV_PREFIX_SID_EFLG);
new->label_in = index2label(new->sid, OspfSR.self->srgb);
new->nhlfe.label_out = MPLS_LABEL_IMPLICIT_NULL;
}
/* Set EXPLICIT NULL flag is present */
if (argv_find(argv, argc, "explicit-null", &idx)) {
SET_FLAG(new->flags, EXT_SUBTLV_PREFIX_SID_NPFLG);
SET_FLAG(new->flags, EXT_SUBTLV_PREFIX_SID_EFLG);
}
osr_debug("SR (%s): Add new index %u to Prefix %pFX", __func__, index,
(struct prefix *)&new->prefv4);
@ -2369,27 +2421,16 @@ DEFUN (sr_prefix_sid,
}
new->nhlfe.ifindex = ifp->ifindex;
/* Search if this prefix already exist */
for (ALL_LIST_ELEMENTS_RO(OspfSR.self->ext_prefix, node, srp)) {
if ((IPV4_ADDR_SAME(&srp->prefv4.prefix, &p.u.prefix4)
&& srp->prefv4.prefixlen == p.prefixlen))
break;
else
srp = NULL;
}
/* Update or Add this new SR Prefix */
if (srp) {
listnode_delete(OspfSR.self->ext_prefix, srp);
/* Add this new SR Prefix if not already found */
if (srp != new)
listnode_add(OspfSR.self->ext_prefix, new);
} else {
listnode_add(OspfSR.self->ext_prefix, new);
}
/* Install Prefix SID if SR is UP */
if (OspfSR.status == SR_UP)
ospf_zebra_update_prefix_sid(new);
else
/* Install Prefix SID if SR is UP and a valid input label set */
if (OspfSR.status == SR_UP) {
if (CHECK_FLAG(new->flags, EXT_SUBTLV_PREFIX_SID_NPFLG)
&& !CHECK_FLAG(new->flags, EXT_SUBTLV_PREFIX_SID_EFLG))
ospf_zebra_update_prefix_sid(new);
} else
return CMD_SUCCESS;
/* Finally, update Extended Prefix LSA id SR is UP */
@ -2406,14 +2447,15 @@ DEFUN (sr_prefix_sid,
DEFUN (no_sr_prefix_sid,
no_sr_prefix_sid_cmd,
"no segment-routing prefix A.B.C.D/M [index (0-65535) no-php-flag]",
"no segment-routing prefix A.B.C.D/M [index (0-65535)|no-php-flag|explicit-null]",
NO_STR
SR_STR
"Prefix SID\n"
"IPv4 Prefix as A.B.C.D/M\n"
"SID index for this prefix in decimal (0-65535)\n"
"Index value inside SRGB (lower_bound < index < upper_bound)\n"
"Don't request Penultimate Hop Popping (PHP)\n")
"Don't request Penultimate Hop Popping (PHP)\n"
"Upstream neighbor must replace prefix-sid with explicit null label\n")
{
int idx = 0;
struct prefix p;
@ -2468,8 +2510,9 @@ DEFUN (no_sr_prefix_sid,
osr_debug("SR (%s): Remove Prefix %pFX with index %u", __func__,
(struct prefix *)&srp->prefv4, srp->sid);
/* Delete NHLFE if NO-PHP is set */
if (CHECK_FLAG(srp->flags, EXT_SUBTLV_PREFIX_SID_NPFLG))
/* Delete NHLFE if NO-PHP is set and EXPLICIT NULL not set */
if (CHECK_FLAG(srp->flags, EXT_SUBTLV_PREFIX_SID_NPFLG)
&& !CHECK_FLAG(srp->flags, EXT_SUBTLV_PREFIX_SID_EFLG))
ospf_zebra_delete_prefix_sid(srp);
/* OK, all is clean, remove SRP from SRDB */
@ -2491,7 +2534,10 @@ static char *sr_op2str(char *buf, size_t size, mpls_label_t label_in,
snprintf(buf, size, "Pop(%u)", label_in);
break;
case MPLS_LABEL_IPV4_EXPLICIT_NULL:
snprintf(buf, size, "Swap(%u, null)", label_in);
if (label_in == MPLS_LABEL_IPV4_EXPLICIT_NULL)
snprintf(buf, size, "no-op.");
else
snprintf(buf, size, "Swap(%u, null)", label_in);
break;
case MPLS_INVALID_LABEL:
snprintf(buf, size, "no-op.");

View File

@ -112,10 +112,10 @@
{
"prefix":"10.0.255.1\/32",
"sid":100,
"inputLabel":20100,
"inputLabel":0,
"prefixRoute":[
{
"outputLabel":3,
"outputLabel":0,
"interface":"lo",
"nexthop":"10.0.255.1"
}

View File

@ -18,6 +18,6 @@ router ospf
segment-routing on
segment-routing node-msd 16
segment-routing global-block 20000 29999
segment-routing prefix 10.0.255.1/32 index 100 no-php-flag
segment-routing prefix 10.0.255.1/32 index 100 explicit-null
!

View File

@ -1,19 +1,4 @@
[
{
"inLabel":20100,
"installed":true,
"nexthops":[
{
"type":"SR (OSPF)",
"outLabel":3,
"outLabelStack":[
3
],
"distance":150,
"installed":true
}
]
},
{
"inLabel":20200,
"installed":true,
@ -43,20 +28,13 @@
"nexthops":[
{
"type":"SR (OSPF)",
"outLabel":8300,
"outLabel":16300,
"outLabelStack":[
8300
16300
],
"distance":150,
"installed":true,
"nexthop":"10.0.1.2"
},
{
"type":"SR (OSPF)",
"outLabel":16300,
"distance":150,
"installed":true,
"nexthop":"10.0.0.2"
}
]
},
@ -66,20 +44,13 @@
"nexthops":[
{
"type":"SR (OSPF)",
"outLabel":8400,
"outLabel":16400,
"outLabelStack":[
8400
16400
],
"distance":150,
"installed":true,
"nexthop":"10.0.1.2"
},
{
"type":"SR (OSPF)",
"outLabel":16400,
"distance":150,
"installed":true,
"nexthop":"10.0.0.2"
}
]
},

View File

@ -166,12 +166,12 @@
"inputLabel":16100,
"prefixRoute":[
{
"outputLabel":20100,
"outputLabel":0,
"interface":"r2-eth0",
"nexthop":"10.0.0.1"
},
{
"outputLabel":20100,
"outputLabel":0,
"interface":"r2-eth1",
"nexthop":"10.0.1.1"
}

View File

@ -5,9 +5,9 @@
"nexthops":[
{
"type":"SR (OSPF)",
"outLabel":20100,
"outLabel":0,
"outLabelStack":[
20100
0
],
"distance":150,
"installed":true,
@ -15,7 +15,7 @@
},
{
"type":"SR (OSPF)",
"outLabel":20100,
"outLabel":0,
"distance":150,
"installed":true,
"nexthop":"10.0.0.1"

View File

@ -5,9 +5,9 @@
"nexthops":[
{
"type":"SR (OSPF)",
"outLabel":8100,
"outLabel":16100,
"outLabelStack":[
8100
16100
],
"distance":150,
"installed":true,
@ -37,9 +37,9 @@
"nexthops":[
{
"type":"SR (OSPF)",
"outLabel":8400,
"outLabel":16400,
"outLabelStack":[
8400
16400
],
"distance":150,
"installed":true,

View File

@ -5,9 +5,9 @@
"nexthops":[
{
"type":"SR (OSPF)",
"outLabel":8100,
"outLabel":16100,
"outLabelStack":[
8100
16100
],
"distance":150,
"installed":true,
@ -37,9 +37,9 @@
"nexthops":[
{
"type":"SR (OSPF)",
"outLabel":8300,
"outLabel":16300,
"outLabelStack":[
8300
16300
],
"distance":150,
"installed":true,