Subject: [netmod] leafref value space and constraint

From: Martin Bjorklund <[email-masked]>
Date: Mon, 23 May 2016 16:10:38 +0200 (CEST)

Hi,

This comment from the Gen-ART review deserves it's own thread.

gen-art> - section 9.9
gen-art> 
gen-art>    The leafref type is used to declare a constraint on the value space
gen-art>    of a leaf, based on a reference to a set of leaf instances in the
gen-art>    data tree.  The "path" substatement (Section 9.9.2) selects a set of
gen-art>    leaf instances, and the leafref value space is the set of values of
gen-art>    these leaf instances.
gen-art> 
gen-art> The first sentence isn't quite right.  Perhaps:
gen-art> 
gen-art>    The value space of a leaf with leafref type is one of the values of
gen-art>    a set of leaf instances in the data tree.  The "path" substatement
gen-art>    (Section 9.9.2) selects the set of leaf instances, and the leafref
gen-art>    value space is the set of values of these leaf instances.
gen-art>
gen-art> - section 9.9.3
gen-art> 
gen-art>    If "require-instance" is "true", it means that the instance being
gen-art>    referred MUST exist for the data to be valid.  This constraint is
gen-art>    enforced according to the rules in Section 8.
gen-art> 
gen-art>    If "require-instance" is "false", it means that the instance being
gen-art>    referred MAY exist in valid data.
gen-art> 
[...]
gen-art> Also, I think the second paragraph means that if require-instance is
gen-art> false, the referred-to instance need not exist.  But it's not clear to
gen-art> me what that would mean -- if there are no instances referenced by the
gen-art> XPath expression, then the set of value values of the leafref would be
gen-art> empty and the leafref would necessarily be invalid. ...  I think these
gen-art> paragraphs need to be expanded in some way.

mbj> Right; so what we want to say is:
mbj> 
mbj>   - the value space is the same as the value space of the referred
mbj>     leaf
mbj> 
mbj>   - there is an additional constraint if require-instance is true that
mbj>     the referred to leaf instance must exist
mbj> 
mbj> How about
mbj> 
mbj> OLD:
mbj> 
mbj>    The leafref type is used to declare a constraint on the value space
mbj>    of a leaf, based on a reference to a set of leaf instances in the
mbj>    data tree.  The "path" substatement (Section 9.9.2) selects a set of
mbj>    leaf instances, and the leafref value space is the set of values of
mbj>    these leaf instances.
mbj> 
mbj>    If the leaf with the leafref type represents configuration data, and
mbj>    the "require-instance" property (Section 9.9.3) is "true", the leaf
mbj>    it refers to MUST also represent configuration.  Such a leaf puts a
mbj>    constraint on valid data.  All such nodes MUST reference existing
mbj>    leaf instances or leafs with default values in use (see Section 7.6.1
mbj>    and Section 7.7.2) for the data to be valid.  This constraint is
mbj>    enforced according to the rules in Section 8.
mbj> 
mbj> NEW:
mbj> 
mbj>    The leafref type is used to declare a constraint on the value space
mbj>    of a leaf, based on a reference to a set of leaf instances in the
mbj>    data tree.  The "path" substatement (Section 9.9.2) is used to refer
mbj>    to another leaf node.  The leafref value space is the value space of
mbj>    this leaf node.
mbj> 
mbj>    If the "require-instance" property is "true", there MUST exist an
mbj>    instance, or a leaf with a default value in use (see Section 7.6.1
mbj>    and Section 7.7.2), of the leaf being referred to with the same value
mbj>    as the leafref value in a valid data tree.
mbj> 
mbj>    If the leaf with the leafref type represents configuration data, and
mbj>    the "require-instance" property (Section 9.9.3) is "true", the leaf
mbj>    it refers to MUST also represent configuration.

Does anyone have comments on this proposal?

/martin

---

From: Ladislav Lhotka <[email-masked]>
Date: Mon, 23 May 2016 17:29:42 +0200

> On 23 May 2016, at 16:10, Martin Bjorklund <[email-masked]> wrote:
> 
> Hi,
> 

This mixes up paths in the data tree with those in the schema tree. The XPath expression in the "path" statement is evaluated in the context of a data tree, but if the result is an empty node set, then "this leaf node" makes no sense.

A specific example:

leaf fooref {
  type leafref {
    path "../foo";
    require-instance false;
  }
}

leaf foo {
  type uint8;
  when "../bar < 42";
}

leaf bar {   
  type uint8;
  default 100;
}

If there is neither "foo" nor "bar" in the data tree, what is the value space of "fooref"?

Lada

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

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

---

From: Martin Bjorklund <[email-masked]>
Date: Mon, 23 May 2016 20:05:44 +0200 (CEST)

Ladislav Lhotka <[email-masked]> wrote:
> This mixes up paths in the data tree with those in the schema
> tree. The XPath expression in the "path" statement is evaluated in
> the context of a data tree, but if the result is an empty node set,
> then "this leaf node" makes no sense.

The fact is that the path statement refers to instances of one leaf
node which exists in the schema tree.  The current text doesn't really
work with "require-instance false".  For example:

   list interface
     leaf name {
       type string;
     }
   }

   leaf if-ref {
     type leafref {
       path /interface/name;
       require-instance false;
     }
   }

The idea is that this would be valid:

  <interface>
    <name>eth0</name>
  </interface>

  <if-ref>eth2</if-ref>

The current text says that the value space of "if-ref" is { "eth0" },
but the intention is to be able to refer to "non-existing values".

The current text also doesn't allow non-existing references in
the candidate.

> If there is neither "foo" nor "bar" in the data tree, what is the

With the new text it would be uint8.

/martin

---

From: Juergen Schoenwaelder <[email-masked]>
Date: Tue, 24 May 2016 10:15:08 +0200

On Mon, May 23, 2016 at 05:29:42PM +0200, Ladislav Lhotka wrote:

[...]
 
> If there is neither "foo" nor "bar" in the data tree, what is the value space of "fooref"?

Hm. Is it not both? The path refers to a schema node in order to
determine the base type (which is the base value set if
require-instance is false). If require-instance is true, then there is
an additional constraint that refers to a set of data nodes that
essentially determine a (possibly empty) subset of the value space.

If you agree with this, then we essentially have to phrase this
clearly.

/js

-- 
Juergen Schoenwaelder           Jacobs University Bremen gGmbH
Phone: +49 421 200 3587         Campus Ring 1 | 28759 Bremen | Germany
Fax:   +49 421 200 3103         <http://www.jacobs-university.de/>

---

From: Martin Bjorklund <[email-masked]>
Date: Tue, 24 May 2016 10:33:29 +0200 (CEST)

> If you agree with this, then we essentially have to phrase this

Exactly.  My proposal was:

OLD:

   The leafref type is used to declare a constraint on the value space
   of a leaf, based on a reference to a set of leaf instances in the
   data tree.  The "path" substatement (Section 9.9.2) selects a set of
   leaf instances, and the leafref value space is the set of values of
   these leaf instances.

   If the leaf with the leafref type represents configuration data, and
   the "require-instance" property (Section 9.9.3) is "true", the leaf
   it refers to MUST also represent configuration.  Such a leaf puts a
   constraint on valid data.  All such nodes MUST reference existing
   leaf instances or leafs with default values in use (see Section 7.6.1
   and Section 7.7.2) for the data to be valid.  This constraint is
   enforced according to the rules in Section 8.

NEW:

   The leafref type is used to declare a constraint on the value space
   of a leaf, based on a reference to a set of leaf instances in the
   data tree.  The "path" substatement (Section 9.9.2) is used to refer
   to another leaf node.  The leafref value space is the value space of
   this leaf node.

   If the "require-instance" property is "true", there MUST exist an
   instance, or a leaf with a default value in use (see Section 7.6.1
   and Section 7.7.2), of the leaf being referred to with the same value
   as the leafref value in a valid data tree.

   If the leaf with the leafref type represents configuration data, and
   the "require-instance" property (Section 9.9.3) is "true", the leaf
   it refers to MUST also represent configuration.

Please comment and/or suggest improvements to this proposal.

/martin

---

From: Ladislav Lhotka <[email-masked]>
Date: Tue, 24 May 2016 11:56:01 +0200

> On 24 May 2016, at 10:33, Martin Bjorklund <[email-masked]> wrote:
> 

The path argument is XPath (in particular, it can contain key value predicates that can be interpreted only in an instance data tree), so it doesn't refer to a schema node.

>   to another leaf node.  The leafref value space is the value space of

The "path" expression is evaluated in some context that's defined in the text. The result is a node set in the *instance* data tree, and in my example this node set is empty.

Yes, I understand that *usually* there is some leaf node in the schema that defines the type of the leafs selected by the XPath expression (if they existed), but I think it is problematic to simply say that an XPath expression refers to a schema node.

Consider the example in Appendix A of RFC 7223. If I have a leafref path like

"/if:interfaces/if:interface[name='at-0/0/0']/eth:duplex"

then if 'at-0/0/0' isn't an Ethernet interface, it doesn't refer to any leaf node because "eth:duplex" is not valid for that particular path expression.

Lada

---

From: Juergen Schoenwaelder <[email-masked]>
Date: Tue, 24 May 2016 11:56:09 +0200

> Please comment and/or suggest improvements to this proposal.

I will give it a try. I think it is helpful to define referring node
and referred node and I think it is useful to first state the purpose
of the leafref type.

  The leafref type is restricted to the value set of some leaf node in
  the schema tree and optionally further restricted by corresponding
  instance nodes in the data tree. More precisely, the leafref type
  declares a constraint on the value space of a leaf node (the
  referring leaf node), based on a reference to a another leaf node in
  the schema tree (the referred leaf node). The "path" substatement
  (Section 9.9.2) is used to identify the referred leaf node in the
  schema tree. The value set of the referring leaf node is the value
  set of the referred leaf node if the "require-instance" property is
  "false".

  If the "require-instance" property is "true", there MUST exist an node
  in the data tree, or a node with a default value in use (see Section
  7.6.1 and Section 7.7.2), of the referred schema tree leaf node with
  the same value as the leafref value in a valid data tree.

  If the referring leaf node represents configuration data, and the
  "require-instance" property (Section 9.9.3) is "true", the referred
  leaf node MUST also represent configuration.

/js

---

From: Martin Bjorklund <[email-masked]>
Date: Tue, 24 May 2016 12:04:54 +0200 (CEST)

Ladislav Lhotka <[email-masked]> wrote:
> >>> tree. The XPath expression in the "path" statement is evaluated in the
> >>> context of a data tree, but if the result is an empty node set, then
> >>> "this leaf node" makes no sense.
> >>> 
> >>> A specific example:
> >>> 
> >>> leaf fooref {
> >>>  type leafref {
> >>>    path "../foo";
> >>>    require-instance false;
> >>>  }
> >>> }
> >>> 
> >>> leaf foo {
> >>>  type uint8;
> >>>  when "../bar < 42";
> >>> }
> >>> 
> >>> leaf bar {   
> >>>  type uint8;
> >>>  default 100;
> >>> }
> >>> 
> The path argument is XPath (in particular, it can contain key value
> predicates that can be interpreted only in an instance data tree), so
> it doesn't refer to a schema node.

Note that is a very restricted XPath expression.  The key values are
only used in predicates, and the predicates don't affect the location
path.

> The "path" expression is evaluated in some context that's defined in
> the text. The result is a node set in the *instance* data tree, and in
> my example this node set is empty.
> 
> Yes, I understand that *usually* there is some leaf node in the schema
> that defines the type of the leafs selected by the XPath expression
> (if they existed), but I think it is problematic to simply say that an
> XPath expression refers to a schema node.
> 
> then if 'at-0/0/0' isn't an Ethernet interface, it doesn't refer to
> any leaf node because "eth:duplex" is not valid for that particular
> path expression.

Correct, so the value space would be the value space of eth:duplex.
The additional constraint would always evaluate to false if there is
never an interface 'at-0/0/0'.

/martin

---

From: Martin Bjorklund <[email-masked]>
Date: Tue, 24 May 2016 12:13:04 +0200 (CEST)

Juergen Schoenwaelder <[email-masked]> wrote:
> and referred node

Ok.

> and I think it is useful to first state the purpose
> of the leafref type.
> 

Maybe remove the second sentence.  Also s/value set/value space/.
Also the last sentence isn't correct; the value space is always the
value space of the referred node.

>   leaf node MUST also represent configuration.

Also, the text needs to mention leaf-lists.  This gives:

  The leafref type is restricted to the value space of some leaf or
  leaf-list node in the schema tree and optionally further restricted
  by corresponding instance nodes in the data tree.  The "path"
  substatement (Section 9.9.2) is used to identify the referred leaf
  or leaf-list node in the schema tree. The value space of the
  referring node is the value space of the referred node.

  If the "require-instance" property is "true", there MUST exist an
  node in the data tree, or a node with a default value in use (see
  Section 7.6.1 and Section 7.7.2), of the referred schema tree leaf
  or leaf-list node with the same value as the leafref value in a
  valid data tree.

  If the referring node represents configuration data, and the
  "require-instance" property (Section 9.9.3) is "true", the referred
  node MUST also represent configuration.

/martin

---

From: Juergen Schoenwaelder <[email-masked]>
Date: Tue, 24 May 2016 12:18:36 +0200

>   node MUST also represent configuration.

Works for me.

/js

---

From: Ladislav Lhotka <[email-masked]>
Date: Tue, 24 May 2016 12:42:46 +0200

> On 24 May 2016, at 12:04, Martin Bjorklund <[email-masked]> wrote:
> 

But the one below is valid, right? You have always insisted that schema nodes for which "when" expression evaluates to false are not part of the schema, which means that different entries of the same list may have different schemas, and predicates then affect the location path - "if:interface" is an example. 

> never an interface 'at-0/0/0'.

There can be one:

"interface": {
   "name": "at-0/0/0",
   "type": "ianaift:atm",
   ...
}

According to sec. 7.21.5, the leaf node "eth:duplex" is invalid in this entry, so it makes no sense to talk about its value space.

Lada

---

From: Martin Bjorklund <[email-masked]>
Date: Tue, 24 May 2016 13:21:40 +0200 (CEST)

Ladislav Lhotka <[email-masked]> wrote:
> But the one below is valid, right?

Yes.

> You have always insisted that
> schema nodes for which "when" expression evaluates to false are not
> part of the schema

I don't think I used that wording...

> which means that different entries of the same
> list may have different schemas, and predicates then affect the
> location path - "if:interface" is an example.
> 
> > 
> According to sec. 7.21.5, the leaf node "eth:duplex" is invalid in
> this entry, so it makes no sense to talk about its value space.

I don't agree that "when" or "if-feature" removes nodes from the
*schema*.  The text says that they make these nodes invalid (scoped to
the parent).

So, imo, eth:duplex does exist in the schema (but will be invalid in
this case).

/martin

---

From: t.petch <[email-masked]>
Date: Fri, 27 May 2016 18:30:13 +0100

----- Original Message -----
From: "Martin Bjorklund" <[email-masked]>
To: <[email-masked]>
Sent: Monday, May 23, 2016 3:10 PM
> Does anyone have comments on this proposal?

yes!

I realise that the discussion is moving on, and corner cases are
appearing, but I think that the NEW paragraph is still a tough read.  I
rearrange the words  - more or less  -and get

NEW

The leafref type is used to declare a constraint on the value space of a
leaf.

The "path" substatement (Section 9.9.2) which MUST be present references
another leaf node. The value space of this other leaf node defines a set
of values, which may be empty (e.g. when the leaf node is not present in
the data tree).

If the "require-instance" property is "true", then the value of the leaf
with the leafref type MUST exist in the set of values; the set of value
includes leafs with have a default value in use (see Section 7.6.1  and
Section 7.7.2)

 If the leaf with the leafref type represents configuration data, and
the "require-instance" property (Section 9.9.3) is "true", then the
target of the "path" substatement MUST also represent configuration
data.

Tom Petch

---

From: Ladislav Lhotka <[email-masked]>
Date: Mon, 30 May 2016 09:26:18 +0200

> On 27 May 2016, at 19:30, t.petch <[email-masked]> wrote:
> 
> 

I think this not correct. Unlike RFC 6020, the "path" argument is now used for two different purposes:

1. It is evaluated as an XPath expression against an instance document (datastore), which results in a node set. If "require-instance" is true, then at least one node in that node set must have the same value as the leaf with leafref type. This is the original 6020 meaning.

2. It also implicitly refers to a leaf node in the schema, and the *type* of this other leaf node determines the type and set of valid values for the leaf with learef type. This is independent of the "require-instance" value and any datastore content. However, any semantic constraints that may apply to the other leaf (such as "must" statements) are not taken into account.     

Lada

---

From: Martin Bjorklund <[email-masked]>
Date: Mon, 30 May 2016 09:43:14 +0200 (CEST)

Ladislav Lhotka <[email-masked]> wrote:
> I think this not correct.

I agree.  Tom, note that the proposal has gone through a couple of
iterations already.  The latest proposal is in
https://mailarchive.ietf.org/arch/msg/netmod/V3-S4enTYpWM24Ws5DWYpEKIq3I

> Unlike RFC 6020, the "path" argument is now
> used for two different purposes:
> 
> 1. It is evaluated as an XPath expression against an instance document
> (datastore), which results in a node set. If "require-instance" is
> true, then at least one node in that node set must have the same value
> as the leaf with leafref type. This is the original 6020 meaning.

Maybe.  6020 also says:

   If the leaf with the leafref type represents configuration data, the
   leaf it refers to MUST also represent configuration.  Such a leaf
   puts a constraint on valid data.  All leafref nodes MUST reference
   existing leaf instances or leafs with default values in use (see
   Section 7.6.1) for the data to be valid.  This constraint is enforced
   according to the rules in Section 8.

which indicates that the intention is that the constraint is *only*
enforced in "valid data".

I think that this is a bug in 6020.

I'm pretty sure that no implementation has implemented this the way it
is described.  Specifically, I think that implementations that support
the candidate datastore allows "non-existing" leafrefs in the
candidate.

/martin

> 2. It also implicitly refers to a leaf node in the schema, and the
> *type* of this other leaf node determines the type and set of valid
> values for the leaf with learef type. This is independent of the
> "require-instance" value and any datastore content. However, any
> semantic constraints that may apply to the other leaf (such as "must"
> statements) are not taken into account.
> 
> Lada
> 
> >

---

From: Ladislav Lhotka <[email-masked]>
Date: Mon, 30 May 2016 10:05:28 +0200

> On 30 May 2016, at 09:43, Martin Bjorklund <[email-masked]> wrote:
> 

Hmm, I agree the second sentence in the original formulation was unclear, but I've always thought it meant simply "Such a leaf introduces a semantic constraint", and that's also how it is handled in DSDL (see sec. 12.10 in RFC 6110).

Note that the phrase "put/declare a constraint on valid data" is used in other places in 6020bis. If the meaning is different from the above, then I am confused.  

> the candidate datastore allows "non-existing" leafrefs in the

Isn't it what sec. 8.3.3 in RFC 6020 prescribes?

   If the datastore is <candidate/>, the constraint enforcement is delayed
   until a <commit> or <validate> operation.

Lada

---

From: Martin Bjorklund <[email-masked]>
Date: Mon, 30 May 2016 10:14:44 +0200 (CEST)

Ladislav Lhotka <[email-masked]> wrote:
> Hmm, I agree the second sentence in the original formulation was
> unclear, but I've always thought it meant simply "Such a leaf
> introduces a semantic constraint", and that's also how it is handled
> in DSDL (see sec. 12.10 in RFC 6110).
> 
> Note that the phrase "put/declare a constraint on valid data" is used
> in other places in 6020bis. If the meaning is different from the
> above, then I am confused.

See below.

>    until a <commit> or <validate> operation.

Right; so the bug in 6020 is this text:

   The "path" substatement (Section 9.9.2) selects a set
   of leaf instances, and the leafref value space is the set of values
   of these leaf instances.

This is not correct for the candidate.  This text means for example
that if there are no target instances in the candidate, the value
space for the leafref would be empty, and it wouldn't be possible to
set the leafref leaf in the candidate.

Hence the proposal to fix this bug in 6020.

/martin

---

From: Ladislav Lhotka <[email-masked]>
Date: Mon, 30 May 2016 10:41:45 +0200

>   referring node is the value space of the referred node.

The term "value space" is not defined in 6020bis, but IMO this is not correct.
For example:

  leaf foo {
    type uint8;
    must ". mod 2 = 0";
  }

Arguably, the value space of this leaf consists only of even numbers. If
"bar" is a leafref that refers to "foo", what is its value space? My
understanding is that it is the whole uint8 range, i.e. the value space
of the *type* of "foo".

Lada

---

From: Martin Bjorklund <[email-masked]>
Date: Mon, 30 May 2016 10:49:24 +0200 (CEST)

Ladislav Lhotka <[email-masked]> wrote:
> Arguably, the value space of this leaf consists only of even
> numbers.

No.  The value space is all of uint8.  In the candidate you can have
foo = 43.

The "must" expression adds a constraint.

> If

Yes.

/martin

---

From: Ladislav Lhotka <[email-masked]>
Date: Mon, 30 May 2016 10:58:44 +0200

> On 30 May 2016, at 10:49, Martin Bjorklund <[email-masked]> wrote:
> 

Then a definition of "value space" needs to be added to the Terminology section. So far, this term has been used in 6020bis only in relation to a data type, not a leaf/leaf-list instance.

Lada

---

From: Ladislav Lhotka <[email-masked]>
Date: Mon, 30 May 2016 11:09:17 +0200

> On 30 May 2016, at 10:58, Ladislav Lhotka <[email-masked]> wrote:
> 
>> 

Here is a suggestion:

o value space: For a data type, it is the set of values permitted by the data type. For a leaf or leaf-list instance, it is the value  space of its data type.

Lada

---

From: Martin Bjorklund <[email-masked]>
Date: Mon, 30 May 2016 12:10:50 +0200 (CEST)

Ladislav Lhotka <[email-masked]> wrote:
> o value space: For a data type, it is the set of values permitted by
>   the data type. For a leaf or leaf-list instance, it is the value
>   space of its data type.

Ok, but s/instance/node/.

/martin

---

From: Ladislav Lhotka <[email-masked]>
Date: Mon, 30 May 2016 12:30:47 +0200

> On 30 May 2016, at 12:10, Martin Bjorklund <[email-masked]> wrote:
> 

Yes, right.

Lada