]> git.proxmox.com Git - mirror_frr.git/commitdiff
OSPFd: Explicit Null option for Segment-Routing
authorOlivier Dugeon <olivier.dugeon@orange.com>
Wed, 8 Jul 2020 18:12:19 +0000 (20:12 +0200)
committerOlivier Dugeon <olivier.dugeon@orange.com>
Thu, 20 Aug 2020 13:51:48 +0000 (15:51 +0200)
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>
doc/user/ospfd.rst
ospfd/ospf_sr.c
tests/topotests/ospf-sr-topo1/r1/ospf_srdb.json
tests/topotests/ospf-sr-topo1/r1/ospfd.conf
tests/topotests/ospf-sr-topo1/r1/zebra_mpls.json
tests/topotests/ospf-sr-topo1/r2/ospf_srdb.json
tests/topotests/ospf-sr-topo1/r2/zebra_mpls.json
tests/topotests/ospf-sr-topo1/r3/zebra_mpls.json
tests/topotests/ospf-sr-topo1/r4/zebra_mpls.json

index ef3eb3851091e93fd6c3726140bcbcafa39b0ebd..19cafa948429a3573a59f191e79fdd2860c0c450 100644 (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]
index ebc31a90f489f6d8450ec29d19989b6a7ec380eb..f6a190db80d7b8b92f80e0776ab8b29385fa499a 100644 (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.");
index 57bcbaeffccf3d6624cd6b5868fe41594d7481c7..952a26ed106791801f13bc8630d44774749f93ca 100644 (file)
         {
           "prefix":"10.0.255.1\/32",
           "sid":100,
-          "inputLabel":20100,
+          "inputLabel":0,
           "prefixRoute":[
             {
-              "outputLabel":3,
+              "outputLabel":0,
               "interface":"lo",
               "nexthop":"10.0.255.1"
             }
index f8fac2428c41f0f3473d4c8b8cf3d0c6c9d8a676..73a272786cf126487469810c47a431690ed3113c 100644 (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
 !
 
index fdf0886bcd6c0bd585f78508fd23bb60b312f0f8..6c87596acb49833347487da812173913e2f4a5fd 100644 (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,
     "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"
       }
     ]
   },
     "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"
       }
     ]
   },
index 6ea0f0a0cf5f57fb161b59f9c422f47d10f18dac..1de780d84ee35e7bc864e4dd2d0500c1237cd8ef 100644 (file)
           "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"
             }
index d343315f0746177b889b3734840e3f8b2321edb9..a885e88fc5a2753037e626961ed70757c5a84670 100644 (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"
index 3d036801d56bb0bf532d07897096d4f39492e913..1b98ff4756b218439f0434b3305797f9d862321e 100644 (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,
index 86ad8721f8d158d422a7dd7654dacfabc99b50a5..b5758f29a0155107fd7386b71715e880fb840abf 100644 (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,