Subject: [yang-doctors] Yangdoctors last call review of draft-ietf-mpls-ldp-yang-06

From: Jan Lindblad via Datatracker <[email-masked]>
Date: Tue, 15 Oct 2019 05:07:05 -0700

Reviewer: Jan Lindblad
Review result: Ready with Issues

Modules: ietf-mpls-ldp.yang, ietf-mpls-ldp-extended.yang
Review result: Ready with Issues
Reviewer: Jan Lindblad

This is my YANG doctor LC review of draft-ietf-mpls-ldp-yang-06. I find the
module ready with issues, even if there are a couple rather fundamental things
to work out. It is evident that the authors have spent considerable time to
make the module clean and tidy, which is why I can say it's more or less ready
even when there are fundamentals to work out. In my judgement it may be
possible to work out all remaining issues rather quickly.

#1) Fitting mpls-ldp into the ietf-routing framework

The modules at hand, ietf-mpls-ldp.yang and ietf-mpls-ldp-extended.yang, are
augmenting into the ietf-routing module (RFC 8022). I find this highly
appropriate. RFC 8022 has a section on how control plane protocols are meant to
fit into the ietf-routing framework:

5.3.2.  Defining New Control-Plane Protocols

   It is expected that future YANG modules will create data models for
   additional control-plane protocol types.  Such a new module has to
   define the protocol-specific configuration and state data, and it has
   to integrate it into the core routing framework in the following way:

   o  A new identity MUST be defined for the control-plane protocol, and
      its base identity MUST be set to "rt:control-plane-protocol" or to
      an identity derived from "rt:control-plane-protocol".
...
   o  Configuration parameters and/or state data for the new protocol
      can be defined by augmenting the "control-plane-protocol" data
      node under both "/routing" and "/routing-state".

The current draft is doing neither of the above two points. IMHO, it should do
both. Or if there is strong reason not to do that, incorporate a statement from
the ietf-routing authors and a clear explanation of why the mpls-ldp related
modules would be exempted. At present, this deviation from the RFC 8022
architecture is never mentioned in the draft.

Even if this issue falls under fundamental issues, the way I look at it, it
would be quite easy to fix. Adjusting the two draft modules to comply with the
points above requires changes to two dozen augment statement paths and a
handful of leafref paths. Adding the identity and corresponding when derived
from statement are a couple of lines.

In principle, this change opens up for multiple instances of mpls-ldp. This
might be useful if a system is used with two entirely separate networks (such
as two separate customers), where each one might be running an mpls-ldp
instance. If this is not desired, a must statement could be introduced to limit
the number of instances to one.

#2) Global level vs. local (e.g. interface or peer) level

The module has several configurations that have a global and local level, such
as configurations per peer or per interface. Presumably, these local level
configurations are meant to override the global default when set and let the
global default prevail when nothing specific is specified at the local level.

The way this is being currently implemented in the modules, however, makes it
impossible not to set a value at the local level, so the local setting will
always prevail. The global configuration would have no effect at all (except in
those cases where a local level configuration is marked with an if-feature and
the server would not announce that feature).

For example:

On the global level, there is a graceful-restart/enable leaf:

      container global {
...
        container graceful-restart {
          leaf enable {
            type boolean;
            default false;
          }

Further down, we have another graceful-restart/enable leaf, used per peer:

  grouping graceful-restart-attributes-per-peer {
...
    container graceful-restart {
      leaf enable {
        type boolean;
        default false;
      }

I would assume this latter enable leaf should take precedence over the global
graceful-restart when set on the peer. But if not set on the peer, the global
graceful-restart value should be used. Since the peer graceful-restart/enable
leaf has a default value, however, it will never happen that it is not set, and
will thus render the global value completely irrelevant for all peers.

The fix is simple: Do not have a default statement on the local leafs. Explain
in the description statement what happens when the element has no value (the
globally configured value will be used). Make sure the global leaf has a
default (they all do already).

The same applies to a rather long list of leafs in the module. I don't dare
listing them here, because I would surely miss a few. My point is that the
global/local relationships needs to be identified, local defaults removed. It
would also make sense to mention how this is supposed to work in the
descriptions.

#3) Unlinked multikey leafrefs

The grouping ldp-peer-ref has two leafrefs, one for each key in the list of ldp
peers. Two leafrefs are exactly what you need to reference an entry in a list
with two keys, so that's good. It is not enough to simply have two unlinked
leafrefs, however. That would still allow them to have values that are valid
separately, but not point to any entry in the list combined. If you have a copy
of "Network Programmability with YANG", this is explained in detail on pp.
451-454.

To link the leafrefs, you'd need to update the path expression in the
label-space-id leaf as follows:

  grouping ldp-peer-ref {
    description
      "An absolute reference to an LDP peer, by the LDP ID, which
       consists of the LSR ID and the Label Space ID.";

    leaf lsr-id {
      type leafref {
        path "/rt:routing/rt:control-plane-protocols/ldp:mpls-ldp/"
          + "ldp:peers/ldp:peer/ldp:lsr-id";
      }
      description
        "The LSR ID of the peer, as a portion of the peer LDP ID.";
    }
    leaf label-space-id {
      type leafref {
        path "/rt:routing/rt:control-plane-protocols/ldp:mpls-ldp/"
          + "ldp:peers/ldp:peer[lsr-id =
          current()/../lsr-id]/ldp:label-space-id";
      }

The paths above would also have to be adjusted as part of fixing issue #1
above. If this fixing results in allowing multiple mpls-ldp instances, the
grouping above needs to be extended with one additional, linked leafref that
points out which mpls-ldp instance is being targeted. Or if that is always the
same instance as the reference is coming from, a reformulation of the paths
above could ensure no mpls-ldp instance name would be required. In that case,
the paths should be relative and never venture outside the mpls-ldp container.
I would be happy to explain this further.

#4) Weakly defined types for neighbor-list-ref, prefix-list-ref, peer-list-ref

These types are not leafrefs, but strings without any YANG substatements to
define the format. The only thing the description does is to claim that the
entities they refer to are outside the scope of this document. For an
operator/programmer encountering this type, that isn't very helpful, and is not
going to be interoperable.

  typedef neighbor-list-ref {
    type string;
    description
      "A type for a reference to a neighbor address list.
       The string value is the name identifier for uniquely
       identifying the referenced address list, which contains a list
       of addresses that a routing policy can applied. The definition
       of such an address list is outside the scope of this
       document.";
  }

I'm not sure if this is fixable by sharpening the YANG module, but maybe more
could be done to guide a confused reader. What would the user do to find out
the format of this type and valid values? Add to the description.

#5) Interfaces or mpls, who's on top?

In the mpls-ldp modules, there are two interface lists and two leafrefs
pointing to interfaces. This makes me wonder if some of the YANG structure
would belong more naturally as an augment to ietf-interfaces instead? I mean,
it doesn't sound fun to define the same interfaces in a lot of different
places, just because a protocol needs some additional information. This is just
a casual observation from an mpls-innocent guy, so you can disregard if you
feel it's irrelevant.

#6) MD5 key

There is a leaf md5-key of type string. Is this leaf sensitive from a security
point of view? A plaintext string would not be ideal if that is the case.
Choose a crypto type instead. Also, the format of this string is not defined.
Hex without spaces? Explain the format in the description.

><

---

From: Martin Bjorklund <[email-masked]>
Date: Tue, 15 Oct 2019 14:25:32 +0200 (CEST)

Hi,

Some comments inline.

> the format of this type and valid values? Add to the description.

If the target of such a reference is outside the scope of this
document, it is reasonable to also leave this leaf as outside the
scope of this document.  When a new module defines such a list, it can
easily augment this module with a proper leafref.   I.e., I suggest
that you can remove this leaf and perhaps explain in text how a future
module can add the reference.

> Choose a crypto type instead.

Or perhaps mark the node with nacm:default-deny-all.

/martin