Subject: [netmod] YANG 1.1 issue: enabled leaf design pattern

From: Andy Bierman <[email-masked]>
Date: Sat, 3 May 2014 09:42:35 -0700

Hi,

Problem:

The use of a leaf in the data model (such as the
/interfaces/interface/enabled
leaf in the ietf-interfaces module) does not account for YANG validation
rules
for many statements that can reference the disabled subtree from outside
of that subtree:

    - must
    - when
    - unique
    - min-elements
    - max-elements
    - leafref (valid instances)
    - choices (disabled case is still the active case, so no other can be
used)

The behavior for all of these statements needs to be clarified
when disabled nodes are involved.

The 'enabled' leaf is like SMIv2 RowStatus TC, except that
it is ad-hoc and used randomly. SMIv2 does not have any
validation statements that can be affected by a 'notInService' row,
so RowStatus is not broken in SNMP.

Solution:

YANG 1.1 must define a "metadata plane" that applies to
configuration datastores.  Global attributes that are specific
to configuration datastores (e.g. with-defaults) will be included
in the standard metadata library. It is expected that protocols
using YANG will define operations for reading and writing
global attributes.

YANG 1.1 must define an "enabled" global attribute that must
be supported in all YANG 1.1 tools. The YANG validation rules
must be adjusted to properly account for disabled subtrees.

Side issue: should 'enabled' leafs be removed when converting
a YANG 1.0 module to YANG 1.1?

Andy

---

From: Ladislav Lhotka <[email-masked]>
Date: Sat, 3 May 2014 20:50:46 +0200

On 03 May 2014, at 18:42, Andy Bierman <[email-masked]> wrote:

> Hi,
> 
> Problem:
> 
> The use of a leaf in the data model (such as the /interfaces/interface/enabled
> leaf in the ietf-interfaces module) does not account for YANG validation rules
>     - choices (disabled case is still the active case, so no other can be used)

In my view, an “enabled false” leaf *operationally* disables a particular instance or function. For all other purposes related to datastore validation, the value of the enabled leaf doesn’t matter. In other words, “enabled false” is not the same as commenting out the corresponding instance in the configuration.

Lada

> _______________________________________________
> netmod mailing list
> [email-masked]
> https://www.ietf.org/mailman/listinfo/netmod

--
Ladislav Lhotka, CZ.NIC Labs
PGP Key ID: E74E8C0C

---

From: Andy Bierman <[email-masked]>
Date: Sat, 3 May 2014 12:31:01 -0700

On Sat, May 3, 2014 at 11:50 AM, Ladislav Lhotka <[email-masked]> wrote:

> In my view, an "enabled false" leaf *operationally* disables a particular
> instance or function. For all other purposes related to datastore
> validation, the value of the enabled leaf doesn't matter. In other words,
> "enabled false" is not the same as commenting out the corresponding
> instance in the configuration.
>
>
OK -- they may be different, but the enabled leaf is ad-hoc,
and YANG designers must know about this leaf.  Adding or removing
this leaf could break other YANG statements.

E,g,

   leaf active-foo-interface {
       type  if:interface-ref;
       mandatory true;
   }

By YANG validation rules, the  leafref test for interface name
will include all disabled interfaces.

Doesn't every object that uses the interface-ref typedef need
to have a must-stmt making sure the enabled leaf is set,
if they want to activate a service on only enabled interfaces?

(Is this the must-stmt to use?)

   leaf active-foo-interface {
       type  if:interface-ref;
       must "/if:interfaces/if:interface[if:name=current()]/enabled";
       mandatory true;
   }

Don't all must/when/leafref validation statements that want only
active interfaces need to be written this way?

I agree this notion of "operationally disabled" is not the
same as commenting out.  I don't think N/Y properly supports
either one.

Lada

Andy

---

From: Ladislav Lhotka <[email-masked]>
Date: Sun, 4 May 2014 09:40:39 +0200

> will include all disabled interfaces.

Yes.

> active interfaces need to be written this way?

I don’t think so. An operator may want to pre-configure an interface in the disabled state, set up all references to it etc., so that everything will be up and running after setting the single “enabled” leaf to true.

Lada

---

From: Andy Bierman <[email-masked]>
Date: Sun, 4 May 2014 01:33:07 -0700

On Sun, May 4, 2014 at 12:40 AM, Ladislav Lhotka <[email-masked]> wrote:

> > In my view, an "enabled false" leaf *operationally* disables a
> particular instance or function. For all other purposes related to
> datastore validation, the value of the enabled leaf doesn't matter. In
> other words, "enabled false" is not the same as commenting out the
> corresponding instance in the configuration.
> >
> >
> I don't think so. An operator may want to pre-configure an interface in
> the disabled state, set up all references to it etc., so that everything
> will be up and running after setting the single "enabled" leaf to true.
>

I said "this is what has to be written to identity active interfaces"
and you respond "maybe they want to select disabled interfaces".
The complex must/when statements will be required to select
active interfaces.  In my example, the active-foo-interface MUST
be active. The foo service does not work when it is configured to
use a disabled interface.  I suspect very few services function correctly
using disabled interfaces.

Andy

---

From: Ladislav Lhotka <[email-masked]>
Date: Sun, 4 May 2014 11:45:06 +0200

On 04 May 2014, at 10:33, Andy Bierman <[email-masked]> wrote:

> and you respond "maybe they want to select disabled interfaces”.

It’s up to the server to interpret the entire configuration, so if a service is enabled in configuration but it depends on an interface that is currently disabled, the server might keep that service operationally disabled as well.

Section 6 in the routing draft deals with exactly these interactions.

If this situation has to be avoided for some reason, then yes, a “must” statement can be used to enforce, e.g., that a leafref only refers to an enabled interface. I don’t see it as a problem though.

I think it is OK that the “enabled” leafs are ad hoc because their semantics may be specific, too.

That said, I am not against introducing the “inactive” attribute but, as I understand it, its meaning will be different.

> using disabled interfaces.

My point is that even if a service looks like being enabled in configuration, it may not be the case because some dependencies are not met - and this can be anticipated, as in the routing data model.

Lada

---

From: Andy Bierman <[email-masked]>
Date: Sun, 4 May 2014 07:11:31 -0700

On Sun, May 4, 2014 at 2:45 AM, Ladislav Lhotka <[email-masked]> wrote:

> It's up to the server to interpret the entire configuration, so if a
> service is enabled in configuration but it depends on an interface that is
> currently disabled, the server might keep that service operationally
> disabled as well.
>
>
Not if the YANG validation rules say differently.
My point is that the YANG designer must write all validation rules to
account for disabled configuration, or the model is wrong.

>
> If this situation has to be avoided for some reason, then yes, a "must"
> statement can be used to enforce, e.g., that a leafref only refers to an
> enabled interface. I don't see it as a problem though.
>
> I think it is OK that the "enabled" leafs are ad hoc because their
> semantics may be specific, too.
>
>
So some enabled leafs will be default true, some default false,
some mandatory with no default.  Some will have special corner-cases
that cause partial operation.  Some will have extra enabled leafs that
change the meaning of the original enabled leaf.

Sounds great if you are trying to create a fragile, ad-hoc, hand-coded
system.
Not so great if you are trying to use YANG to bring consistency and
automation
into the system.

That said, I am not against introducing the "inactive" attribute but, as I
> understand it, its meaning will be different.
>
> My point is that even if a service looks like being enabled in
> configuration, it may not be the case because some dependencies are not met
> - and this can be anticipated, as in the routing data model.
>
>
The system will have to be designed to account for all these ad-hoc on/off
switches.
IMO hindsight will show that a completely free-form solution path was not a
good idea.

Lada

Andy

---

From: Andy Bierman <[email-masked]>
Date: Sun, 4 May 2014 10:16:56 -0700

> semantics may be specific, too.

This is the part I really don't like.
These mechanisms should not be ad-hoc and different for every module.
There should be a standard way to operationally enable/disable config
and a standard way to comment/uncomment config.

IMO, we are making a big mistake by not standardizing a solution like the
xpath1.0
typedef in ietf-yang-types.yang.  If there was a reusable type for this
leaf, then tools
could use that to identify the design pattern and handle the enable/disable
edits
within the validation engine and the system instrumentation.

Sometimes following the CLI too closely leads to bad API decisions

Andy

---

From: Ladislav Lhotka <[email-masked]>
Date: Mon, 05 May 2014 09:08:19 +0200

> account for disabled configuration, or the model is wrong.

I don't agree. It would be extremely impractical to render a configuration invalid just by disabling an interface.

I suspect we (again) run into the confusion of configuration and state. The rules you are talking about are in fact important for operational state - service X cannot be enabled unless interface Y is enabled as well. In configuration they are IMO unnecessary, in fact annoying - the server should be able to figure out what to do.

> change the meaning of the original enabled leaf.

Sure, if it makes sense for a particular case and implementation policy. For example, an implementation might want to have ssh server enabled by default but XMPP server disabled by default.

> Not so great if you are trying to use YANG to bring consistency and

I don't believe there is a one-size-fits-all solution for all these "enabled" switches. In some cases, their effect is combined with parent presence containers.

If there is a prototypical pattern for using such "enabled" leafs, it can be explained in 6087bis, and perhaps supported with some groupings. But this doesn't mean there can't be an "enabled" leaf with different semantics.

Why is that fragile, if the semantics are properly described in the data model?

> IMO hindsight will show that a completely free-form solution path was not a

Free form? I think a data modeller is supposed to do the right thing, and IMO it is not the same in all cases.

Lada

---

From: Martin Bjorklund <[email-masked]>
Date: Mon, 05 May 2014 09:26:32 +0200 (CEST)

> invalid just by disabling an interface.

I think you are both right - the 'inactive' feature is very useful
(and it works just as if the node is deleted), but it doesn't
necessarilty replace an "enabled" leaf in all cases.  As you noted,
they behave differently.

/martin

---

From: Martin Bjorklund <[email-masked]>
Date: Mon, 05 May 2014 09:26:48 +0200 (CEST)

Hi,

Added as Y48.

/martin

---

From: Ladislav Lhotka <[email-masked]>
Date: Mon, 5 May 2014 09:34:57 +0200

> necessarilty replace an "enabled" leaf in all cases.  As you noted,

Yes, that’s what I wrote in my earlier email. But then, any use of ‘inactive’ may of course violate constraints of the data model - exactly as node deletion can. So I don’t see the point of this issue - what needs to be clarified?

Lada

---

From: Andy Bierman <[email-masked]>
Date: Mon, 5 May 2014 01:48:04 -0700

On Mon, May 5, 2014 at 12:26 AM, Martin Bjorklund <[email-masked]> wrote:

> > >> > > >     - choices (disabled case is still the active case, so no
> other
> > >> can be used)
> > >> > >
> > >> > >        must
> "/if:interfaces/if:interface[if:name=current()]/enabled";
> > >> > >        mandatory true;
> > >> > >    }
> > >> > >
> > I don't agree. It would be extremely impractical to render a
> configuration
> > invalid just by disabling an interface.
>
>
The important point is that the designer better know every single
YANG object and write the validation rules correctly.
Inconvenient or not, if some component needs to use
only active interfaces, then ignoring the 'active' leaf will be broken.

The system can be hand-coded at great expense to deal with any
poorly designed ad-hoc mechanism.  It is just engineering decisions
that determine whether we develop an efficient programmatic API
or we develop CLI with angle brackets.

Andy

---

From: Ladislav Lhotka <[email-masked]>
Date: Mon, 5 May 2014 11:36:38 +0200

> only active interfaces, then ignoring the 'active' leaf will be broken.

It will be broken in terms of operational state, not configuration. Many changes in configuration have ripple effects and well-designed server should be able to trace dependencies and act accordingly, rather than forcing the user to do it manually.

> or we develop CLI with angle brackets.

So what would you do with the rules in sec. 6 of the routing module? Note that they involve not only “enabled” leafs in the interfaces and ip modules, but also “ip:forwarding”.

For example, if /if:interfaces/if:interface/if:enabled is set to false for an interface, I don’t want to force the client to go and remove that interface from all configured routing instances.

Similarly, disabling a physical interface should automatically lead to disabling all logical interfaces created on top of that physical interface - without having to disable all of them manually.

Lada

---

From: Andy Bierman <[email-masked]>
Date: Mon, 5 May 2014 08:05:27 -0700

On Mon, May 5, 2014 at 2:36 AM, Ladislav Lhotka <[email-masked]> wrote:

> > > >> > > On Sat, May 3, 2014 at 11:50 AM, Ladislav Lhotka <[email-masked]
> >
> > > >> wrote:
> > > >> > >
> > > >> > > > for many statements that can reference the disabled subtree
> from
> > > >> outside
> > > >> > > > of that subtree:
> > > >> > > >
> > > >> > > >     - must
> > > >> > > >     - when
> > > >> > > >     - unique
> > > >> > > >     - min-elements
> > > >> > > >     - max-elements
> It will be broken in terms of operational state, not configuration. Many
> changes in configuration have ripple effects and well-designed server
> should be able to trace dependencies and act accordingly, rather than
> forcing the user to do it manually.
>
>

The server cannot ripple the disable event automatically using an ad-hoc
solution,
but that is just an implementation detail to the IETF, so it's not
important.

The reason RowStatus is a bad idea is that it is not config, but it is
mixed in
with the config, and it is config according to YANG validation rules.
When you set the enabled leaf to false with an <edit-config> operation,
you are configuring the interface to be operationally disabled.

All YANG validation outside the interface has to account for interfaces
that have been configured to be operationally disabled.

When the hardware is operationally broken, setting 'enable' to true
is not going to fix it.  The enabled leaf is just the desired state, like
all the other config=true nodes.

I agree that the desired state and operational state are not the same.
I don't agree that setting enabled-leaf to false is the same as the system
disabling a broken interface.

Andy

> So what would you do with the rules in sec. 6 of the routing module? Note
> that they involve not only "enabled" leafs in the interfaces and ip
> modules, but also "ip:forwarding".
>
> For example, if /if:interfaces/if:interface/if:enabled is set to false for
> an interface, I don't want to force the client to go and remove that
> interface from all configured routing instances.
>
> Similarly, disabling a physical interface should automatically lead to
> disabling all logical interfaces created on top of that physical interface
> - without having to disable all of them manually.
>
> Lada
>
> >
> >
> >

---

From: Ladislav Lhotka <[email-masked]>
Date: Mon, 5 May 2014 18:25:22 +0200

On 05 May 2014, at 17:05, Andy Bierman <[email-masked]> wrote:

> The server cannot ripple the disable event automatically using an ad-hoc solution,
> but that is just an implementation detail to the IETF, so it's not important.

Of course it can, why not? An implementor of the routing module is expected to follow sec. 6 rules. It is just not so that the same callback can be used whenever any “enabled” leaf is changed.

> 
> The reason RowStatus is a bad idea is that it is not config, but it is mixed in

Yes.

> that have been configured to be operationally disabled.

This is where we differ, as long as you talk about configuration. The ex-vlan module in interfaces draft doesn’t have any must statement requiring that the base-interface be enabled.

> all the other config=true nodes.

Sure.

> disabling a broken interface.

Where did I say that?

Lada

---

From: Andy Bierman <[email-masked]>
Date: Mon, 5 May 2014 10:21:13 -0700

On Mon, May 5, 2014 at 9:25 AM, Ladislav Lhotka <[email-masked]> wrote:

> > > > >> > > On Sat, May 3, 2014 at 11:50 AM, Ladislav Lhotka <
> [email-masked]>
> > > > >> wrote:
> > > > >> > >
> > > > >> > > > leaf in the ietf-interfaces module) does not account for
> YANG
> > > > >> validation rules
> > > > >> > > >     - choices (disabled case is still the active case, so
> no other
> > > > >> can be used)
> > > > >> > >
> Of course it can, why not? An implementor of the routing module is
> expected to follow sec. 6 rules. It is just not so that the same callback
> can be used whenever any "enabled" leaf is changed.
>

I meant "automatically" to be automated, not hand-coded.
The more free-form behavior that is defined in text instead of
some sort of structured statement, the more hand-coding.

> This is where we differ, as long as you talk about configuration. The
> ex-vlan module in interfaces draft doesn't have any must statement
> requiring that the base-interface be enabled.
>
>
The design still has to account for the enabled leaf.
You decided it doesn't matter for that specific ad-hoc case.

Let's say the site has a SLA that says a certain server needs to
always have at least 1 operationally enabled interface at all times.
In that case, the enabled=false interfaces need to be checked.
The operator is not allowed to configure all interfaces to be disabled.

I guess we don't agree that this is some sort of repeatable design pattern
that does not have to be defined in free-form text.

Lada

Andy

> > So what would you do with the rules in sec. 6 of the routing module?
> Note that they involve not only "enabled" leafs in the interfaces and ip
> > For example, if /if:interfaces/if:interface/if:enabled is set to false
> for an interface, I don't want to force the client to go and remove that

---

From: Andy Bierman <[email-masked]>
Date: Mon, 5 May 2014 10:55:23 -0700

Hi,

Here is what I mean by a typedef solution.
Why did the WG decide this cannot work?

OLD:

         leaf enabled {
           type boolean;
           default "true";
           description
             "This leaf contains the configured, desired state of the
              interface.
              Systems that implement the IF-MIB use the value of this
              leaf in the 'running' datastore to set
              IF-MIB.ifAdminStatus to 'up' or 'down' after an ifEntry
              has been initialized, as described in RFC 2863.

              Changes in this leaf in the 'running' datastore are
              reflected in ifAdminStatus, but if ifAdminStatus is
              changed over SNMP, this leaf is not affected.";
           reference
             "RFC 2863: The Interfaces Group MIB - ifAdminStatus";
         }

NEW:

         // this is a general typedef, probably in ietf-yang-types

         typedef oper-enabled {
           type boolean;
           description
             "Used to operationally disable some configuration.
              The affected configuration SHOULD be limited to
              the parent node of the leaf using this typedef,
              but it MAY affect other configuration as described
              in the module.";
         }

         leaf enabled {
           type yang:oper-enabled;
           default "true";
           description
             "This leaf contains the configured, desired state of the
              interface.
              Systems that implement the IF-MIB use the value of this
              leaf in the 'running' datastore to set
              IF-MIB.ifAdminStatus to 'up' or 'down' after an ifEntry
              has been initialized, as described in RFC 2863.

              Changes in this leaf in the 'running' datastore are
              reflected in ifAdminStatus, but if ifAdminStatus is
              changed over SNMP, this leaf is not affected.";
           reference
             "RFC 2863: The Interfaces Group MIB - ifAdminStatus";
         }

Andy

---

From: Martin Bjorklund <[email-masked]>
Date: Mon, 05 May 2014 21:26:46 +0200 (CEST)

> Why did the WG decide this cannot work?

I don't think this was ever proposed and considered by the WG.

/martin

---

From: Ladislav Lhotka <[email-masked]>
Date: Tue, 6 May 2014 06:39:14 +0200

> I don't think this was ever proposed and considered by the WG.

+1

This is doable in good old YANG 1.0.

Lada

---

From: Andy Bierman <[email-masked]>
Date: Tue, 6 May 2014 09:33:51 -0700

> This is doable in good old YANG 1.0.
I proposed a grouping earlier but that was too restrictive.
I realized the default does not matter for tagging purposes.
The exact requirements and effects of disabling are model-specific.

The SHOULD means somebody needs a good reason not to make
the leaf affect just the parent subtree. (Before it was a MUST I think.)

Andy