Subject: [netmod] Questions about namings and prefixes in leafrefs

From: Paul Borman <[email-masked]>
Date: Thu, 22 Jan 2015 05:07:36 +1100

Hi, I am trying to understand RFC6020 without having had the benefit of
being in any of the discussions of the working group.  I have found the
discussion of path names unclear so I have used pyang to try and understand
what is expected.  It seems to me that a path in a leafref:

   - may descend into submodule's containers
   - may descend into used groupings, no matter where the grouping is
   defined
   - may *not* ascend into the parent module
   - may optionally use the module's prefix for any element in a leafref
   path, no matter where the element is defined
   - may optionally use the belongs-to-prefix in elements in paths inside a
   submodule
   - may *never* use the prefix for/from an imported module

Some questions this raise are:

   - are these observations correct (and intended)?
   - is there ever a time where a prefix is required in a leafref path?

Attached are the modules and submodules I used that lead to these
assumptions and questions.  pyang -f tree produces the following errors:

base.yang:50: error: other:other-group-container-leaf1 in the path for
base-container-badref1 at base.yang:49 is not found
base.yang:53: error: prefix "pother" is not defined (reported only once)
sub.yang:15: error: base:base-container in the path for sub-badref2 at
sub.yang:14 is not found
sub.yang:18: error: base:base-container in the path for sub-badref3 at
sub.yang:17 is not found

I am also trying to understand the prefixes used in XPath representations.
I have tried using --tree-prefix but that does not appear to accept any
prefixes.

Thanks for any guidance,

    -Paul

// Base test yang module.
module base {
  namespace "urn:mod";
  prefix "base";

  include sub;
  import other {
    prefix bother;
  }

  grouping base-group {
    leaf base-group-leaf { type string; }
  }

  // test uses and leaf ref
  container base-container {
    uses base-group;
    uses bother:other-group;
    uses base:sub-group;
    leaf base-container-leaf { type string; }
    leaf base-container-ref1 {
      type leafref { path ../base-container-leaf; }
    }
    leaf base-container-ref2 {
      type leafref { path ../base-group-leaf; }
    }
    leaf base-container-ref3 {
      type leafref { path ../other-group-leaf; }
    }
    leaf base-container-ref4 {
      type leafref { path ../sub-group-container/sub-group-leaf; }
    }
    leaf base-container-ref5 {
      type leafref { path ../../base:sub-container/sub-container-leaf; }
    }
    leaf base-container-ref6 {
      type leafref { path ../../base:sub-container/base:sub-container-leaf;
}
    }
    leaf base-container-ref7 {
      type leafref { path ../../sub-container/base:sub-container-leaf; }
    }
    leaf base-container-ref8 {
      type leafref { path
../other-group-container/other-group-container-leaf1; }
    }
    leaf base-container-ref9 {
      type leafref { path
../other-group-container/base:other-group-container-leaf1; }
    }
    // These next two ar invalid
    leaf base-container-badref1 {
      type leafref { path
../other-group-container/bother:other-group-container-leaf1; }
    }
    leaf base-container-badref2 {
      type leafref { path
../other-group-container/pother:other-group-container-leaf1; }
    }
  }
}

// included by base.yang.
submodule sub {
  belongs-to base { prefix "sbase"; }
  container sub-container {
    leaf sub-container-leaf { type string; }
    container subsub {
      leaf sub-leafref {
        type leafref { path ../../sub-container-leaf; }
      }
      leaf sub-leafref1 {
        type leafref { path ../../sbase:sub-container-leaf; }
      }
      // the next two both fail trying to ascend into the parent
      leaf sub-badref2 {
        type leafref { path ../../../base-container/base-container-leaf; }
      }
      leaf sub-badref3 {
        type leafref { path
../../../sbase:base-container/base-container-leaf; }
      }
    }
  }
  grouping sub-group {
    container sub-group-container {
      leaf sub-group-leaf { type string; }
    }
  }
}

// imported by base.yang.
module other {
  namespace "uri:empty";
  prefix "otherp";
  container other-container {
    leaf other-container-leaf1 { type string; }
    leaf other-container-leaf2 { type string; }
  }
  grouping other-group {
    leaf other-group-leaf { type string; }
    container  other-group-container {
      leaf other-group-container-leaf1 { type string; }
      leaf other-group-container-leaf2 { type string; }
    }
  }
}

---

From: Ladislav Lhotka <[email-masked]>
Date: Thu, 22 Jan 2015 14:07:05 +0100

Hi Paul,

>    - may descend into submodule's containers

yes

>    - may descend into used groupings, no matter where the grouping is

yes

>    - may *not* ascend into the parent module

Actually, I am not sure about this one.

>    path, no matter where the element is defined

The prefix has to be present if the node is defined in another
module. For example, a leafref in "base" pointing to
"other-container-leaf1" would have

  path "/bother:other-container/bother:other-container-leaf1";

>    - may optionally use the belongs-to-prefix in elements in paths inside a

yes

>    - may *never* use the prefix for/from an imported module

It must *always* use it.

>    - is there ever a time where a prefix is required in a leafref

Yes, see above.

I hope submodule rules will be significantly simplified in YANG 1.1, see
issue Y49:

https://svn.tools.ietf.org/svn/wg/netmod/yang-1.1/issues.html#sec-50

...

> I have tried using --tree-prefix but that does not appear to accept any

The "tree" plugin has no such option, RTFM.

> ../other-group-container/bother:other-group-container-leaf1; }

The prefix "bother" is wrong. It is because YANG groupings are
"chameleons": nodes defined in a grouping receive the namespace of the
module where the grouping is used, not the one in which it is
defined. Sec sec. 7.12 in RFC 6020.

Lada

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

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

---

From: Paul Borman <[email-masked]>
Date: Thu, 22 Jan 2015 09:43:53 -0800

Thanks for the response and clarification, Lada.

> The "tree" plugin has no such option, RTFM.

Yes, clearly I meant --tree-path.  Sorry to have confused you.  Given the
chameleon aspect of groups, I take it that paths to a node in a data tree
(not the schema tree) do not have prefixes, and --tree-path takes a path in
the data tree (the documentation I read just says "Subtree to print").  I
am actually very happy to not have prefixes in the resulting data tree at
all.

Interesting.  So a path in a leafref references the resulting data tree,
while the path provided to augment references the schema tree.  Re-reading
the "uses" description I see where it switches namespaces.

Since it appears, via empirical evidence with pyang, that the nodes of an
imported tree do not become part of the tree of the importing module.  What
does it mean to have a leafref reference a node in a tree other than its
own?  I will note that my example referred to a node within a grouping
defined in other but used in base, while your example refers to a node that
only exists in other.  So, my assertion about paths (they were all
relative) and prefix names was actually correct, but does not apply when
referencing a node in a different data tree (i.e., not part of the data
tree of the base module), which is what you gave an example of.

The "switching names spaces" aspect of uses explains why I cannot use the
bother prefix in relative paths, or even in paths rooted in base, that
include nodes from a grouping in other.  The satisfaction of types does
seem inconsistent with this, however.  I added some typedefs to base.yang
and other.yang (base-type and other-type, respectively), and then modified
the grouping in other.yang to have:

  grouping other-group {
    leaf other-group-leaf { type other-type; }
    leaf other-base-leaf { type base-type; }
    leaf other-bad-leaf { type bad-type; }
  }

When the other-group is used in base.yang, only bad-type is flagged as not
found (shouldn't other-type also be flagged as not found?), while when
other-group is used in other.yang, both base-type and bad-type are flagged
as not found (as I would expect).

Thanks,

    -Paul

---

From: Ladislav Lhotka <[email-masked]>
Date: Thu, 22 Jan 2015 19:18:37 +0100

> On 22 Jan 2015, at 18:43, Paul Borman <[email-masked]> wrote:
> 
> Yes, clearly I meant --tree-path.  Sorry to have confused you.  Given the chameleon aspect of groups, I take it that paths to a node in a data tree (not the schema tree) do not have prefixes, and --tree-path takes a path in the data tree (the documentation I read just says "Subtree to print").  I am actually very happy to not have prefixes in the resulting data tree at all.

Sometimes they are needed, even in JSON encoding that tries to suppress them as much as possible.
 
> Interesting.  So a path in a leafref references the resulting data tree, while the path provided to augment references the schema tree.  Re-reading the "uses" description I see where it switches

That’s right, augments modify the schema tree.

>  namespaces.
> 
> Since it appears, via empirical evidence with pyang, that the nodes of an imported tree do not become part of the tree of the importing module.  What does it mean to have a leafref reference a node in a

That’s correct, the importing module only gets access to top-level groupings, typedefs, identities and features.

>  tree other than its own?  I will note that my example referred to a node within a grouping defined in

The information about the set of modules that comprise the data model has to be supplied by other means. In NETCONF it is the hello message, and in pyang you can either provide a hello message as an XML document (with the --hello option), or simply put all modules on the command line. In your case it could be

$ pyang -f tree base.yang other.yang

>  other but used in base, while your example refers to a node that only exists in other.  So, my assertion about paths (they were all relative) and prefix names was actually correct, but does not apply when referencing a node in a different data tree (i.e., not part of the data tree of the base module), which is what you gave an example of.
> 
> The "switching names spaces" aspect of uses explains why I cannot use the bother prefix in relative paths, or even in paths rooted in base, that include nodes from a grouping in other.  The satisfaction of types does seem inconsistent with this, however.  I added some typedefs to base.yang and other.yang (base-type and other-type, respectively), and then modified the grouping in other.yang to have:
> 
>   grouping other-group {
> When the other-group is used in base.yang, only bad-type is flagged as not found (shouldn't other-type also be flagged as not found?), while when other-group is used in other.yang, both base-type and bad-type are flagged as not found (as I would expect).

This is not what I get: 

$ pyang base.yang other.yang 
other.yang:15: error: type "base-type" not found in module other
other.yang:16: error: type "bad-type" not found in module other

This is correct because types and everything else in a grouping are resolved in the context of the module where the grouping is defined, only reusable data nodes defined by the grouping receive the namespace of the module where the grouping is used. In your case, “base-type” is not known in “other”.

In the “base” module you could refer to “other-type” but only with the prefix:

type bother:other-type

This is because “base” imports “other”.

Lada

---

From: Paul Borman <[email-masked]>
Date: Thu, 22 Jan 2015 11:32:09 -0800

> other.yang:16: error: type "bad-type" not found in module other

Okay, this appears to be a bug in the tree format:

$ *pyang base.yang 2>&1 | grep -- -type*
other.yang:15: error: type "base-type" not found in module other
other.yang:16: error: type "bad-type" not found in module other
$ *pyang -f tree base.yang 2>&1 | grep -- -type*
      +--rw other-group-leaf?         other-type
      +--rw other-base-leaf?          base-type
      +--rw other-bad-leaf?           bad-type
$ *pyang -f tree base.yang other.yang 2>&1 | grep -- -type*
other.yang:15: error: type "base-type" not found in module other
other.yang:16: error: type "bad-type" not found in module other
      +--rw other-group-leaf?         other-type
      +--rw other-base-leaf?          base-type
      +--rw other-bad-leaf?           bad-type
   +--rw other-group-leaf?        other-type
   +--rw other-base-leaf?         base-type
   +--rw other-bad-leaf?          bad-type

I only specified base.yang as that was the only tree I was interested in.

This research is part of a larger issue of how we are going to be able to
combine various disparate modules defined in YANG into a single tree.  Thus
far it appears that module writers decide where the root of their tree is
and the data tree of one module cannot become part of a tree for another
module.  That is, we cannot write, in pure YANG, a super module that
includes several other modules where those module writers were unaware of
the super module.  It is recursive because we probably will later need a
super super module that is a collection of super modules (and regular
modules).  Currently it appears that modules always know the root of the
tree (either their own or one they augment).  I don't yet see a combination
of include, import, grouping, augment and/or uses that would enable this
ability, but perhaps I am missing something.

Thanks,

    -Paul

On Thu, Jan 22, 2015 at 10:18 AM, Ladislav Lhotka <[email-masked]> wrote:

> > Yes, clearly I meant --tree-path.  Sorry to have confused you.  Given
> the chameleon aspect of groups, I take it that paths to a node in a data
> tree (not the schema tree) do not have prefixes, and --tree-path takes a
> path in the data tree (the documentation I read just says "Subtree to
> print").  I am actually very happy to not have prefixes in the resulting
> data tree at all.
>
> the "uses" description I see where it switches
>
> > Since it appears, via empirical evidence with pyang, that the nodes of
> an imported tree do not become part of the tree of the importing module.
> What does it mean to have a leafref reference a node in a
>
> That’s correct, the importing module only gets access to top-level
> groupings, typedefs, identities and features.
>
> The information about the set of modules that comprise the data model has
> to be supplied by other means. In NETCONF it is the hello message, and in
> pyang you can either provide a hello message as an XML document (with the
> --hello option), or simply put all modules on the command line. In your
> case it could be
>
> >  other but used in base, while your example refers to a node that only
> exists in other.  So, my assertion about paths (they were all relative) and
> prefix names was actually correct, but does not apply when referencing a
> node in a different data tree (i.e., not part of the data tree of the base
> module), which is what you gave an example of.
> >
> > The "switching names spaces" aspect of uses explains why I cannot use
> the bother prefix in relative paths, or even in paths rooted in base, that
> > When the other-group is used in base.yang, only bad-type is flagged as
> not found (shouldn't other-type also be flagged as not found?), while when
> This is correct because types and everything else in a grouping are
> resolved in the context of the module where the grouping is defined, only
> reusable data nodes defined by the grouping receive the namespace of the
> module where the grouping is used. In your case, “base-type” is not known
> in “other”.
>
> ../../../base-container/base-container-leaf; }
> > >       }
> > >       leaf sub-badref3 {
> > >         type leafref { path