libyang icon indicating copy to clipboard operation
libyang copied to clipboard

must evaluated in empty container

Open koalo opened this issue 1 year ago • 5 comments

For the following test.yang

module test {
  yang-version 1.1;
  namespace "urn:ietf:params:xml:ns:test";
  prefix "test";

  container foo {
    leaf x {
      type uint8;
    }

    container bar {
      must "y < ../x";
      leaf y {
        type uint8;
      }
    }
  }
}

and the following test.json

{
  "test:foo": {
    "x": 3
  }
}

the output of yanglint test.yang test.json is

libyang err : Must condition "y < ../x" not satisfied. (Data location "/test:foo/bar".)
YANGLINT[E]: Failed to parse input data file "test.json".

However, RFC 6020 writes If a data node does not exist in the data tree, and it does not have a default value, its "must" statements are not evaluated. so I would expect the must expression is not evaluated in this case.

I noticed that with the must statement in https://github.com/YangModels/yang/blob/3b369b8c147cf0242c0c311ed8fb17f71bdc3ab3/standard/ieee/draft/802.1/Qcw/ieee802-dot1q-sched.yang#L190 that is several layers deep, but is still evaluated. So for example, have a look at the following data:

{
  "ietf-interfaces:interfaces": {
    "interface": [
      {
        "name": "eth0",
        "type": "iana-if-type:ethernetCsmacd",
        "ieee802-dot1q-bridge:bridge-port": {
          "traffic-class": {
            "traffic-class-table": {
              "number-of-traffic-classes": 3,
              "priority0": 2,
              "priority1": 2,
              "priority2": 1,
              "priority3": 0,
              "priority4": 2,
              "priority5": 2,
              "priority6": 2,
              "priority7": 2
            }
          },
          "ieee802-dot1q-sched-bridge:gate-parameter-table": {
            "gate-enabled": true,
            "config-change": true,
            "supported-list-max": 3,
            "supported-interval-max": 1000000,
            "supported-cycle-max": {
              "numerator": 1,
              "denominator": 1
            },
            "admin-cycle-time": {
              "numerator": 1,
              "denominator": 1000
            },
            "admin-base-time": {
              "seconds": "1",
              "nanoseconds": 0
            },
            "admin-control-list": {
              "gate-control-entry": [
                {
                  "index": 0,
                  "operation-name": "ieee802-dot1q-sched:set-gate-states",
                  "time-interval-value": 300000,
                  "gate-states-value": 1
                },
                {
                  "index": 1,
                  "operation-name": "ieee802-dot1q-sched:set-gate-states",
                  "time-interval-value": 300000,
                  "gate-states-value": 3
                },
                {
                  "index": 2,
                  "operation-name": "ieee802-dot1q-sched:set-gate-states",
                  "time-interval-value": 400000,
                  "gate-states-value": 4
                }
              ]
            }
          }
        }
      },
      {
        "name": "eth1",
        "type": "iana-if-type:ethernetCsmacd"
      }
    ]
  }
}

where eth0 is considered valid, but eth1 fails with Number of elements in admin-control-list must not be greaterthan supported-list-max (Data location "/ietf-interfaces:interfaces/interface[name='eth1']/ieee802-dot1q-bridge:bridge-port/ieee802-dot1q-sched-bridge:gate-parameter-table/admin-control-list".)

koalo avatar Dec 08 '23 15:12 koalo

However, RFC 6020 writes If a data node does not exist in the data tree, and it does not have a default value, its "must" statements are not evaluated. so I would expect the must expression is not evaluated in this case.

In the example YANG file, the node itself has no must statement; it's a statement which belongs to the enclosing container. I do not think that the clause you quoted applies here.

jktjkt avatar Dec 11 '23 00:12 jktjkt

I am not sure about the terminology here. However, as you see in the second example, the same problem exists several levels of containers deep.

So either there is a problem in the IEEE YANG model or in libyang. Due to the quoted statement I would tend to the latter (otherwise you need to fulfill "must" statements of branches you might not even be aware of just because a YANG model is loaded), but if you have a convincing argument why the YANG model is wrong, that would also be OK and I would forward it to the IEEE.

koalo avatar Dec 11 '23 07:12 koalo

From RFC 7950:

   In the first style, the container has no meaning of its own, existing
   only to contain child nodes.  In particular, the presence of the
   container node with no child nodes is semantically equivalent to the
   absence of the container node.  YANG calls this style a "non-presence
   container".  This is the default style.

which pretty much contradicts what you quoted:

If a data node does not exist in the data tree, and it does not have a default value, its "must" statements are not evaluated.

because if a NP container has a must, it has some meaning and yet it should not make a difference whether it exists or not. There was some discussion about this on the NETMOD mailing list and libyang behavior was accepted. In this particular case, the container is supposed to have presence to signify that it actually has a meaning.

michalvasko avatar Dec 14 '23 10:12 michalvasko

So, first of all, adding presence statements to each container with must actually leads to the must statement not being evaluated if they do not appear in the data. So that is already good to know.

If I understand you correctly, you are saying that without a presence statement it should not make a difference (i.e. it can not be decided) if a container node itself exists or is absent in the data tree, right?

But the relevant sentence for me in your quote is

In particular, the presence of the [NP] container node with no child nodes is semantically equivalent to the absence of the container node.

In my opinion that means also for a NP container it can be decided if it exists or not (and consequently if the must statement should be evaluated), just the rules are different depending on the availability of the presence statement:

presence available: Container node exists in the data tree if and only if it is explicitly provided, regardless of the existence of child nodes. presence not available: Container node exists if and only if at least one child nodes exists, regardless of the container node itself being explicitly provided.

But there might have been other arguments on the NETMOD mailing list. Unfortunately, I was not able to find the post. The only ones that I found that could be slightly related were https://mailarchive.ietf.org/arch/msg/netmod/5sNvaTjijqcxojEIeb8ntLqKp8E/ https://mailarchive.ietf.org/arch/msg/netmod/fWJzQoTC9VgqSpEGXMG4xuo4uZ4/ but both do not seem to really apply to this scenario. Can you please share a link of that discussion?

koalo avatar Dec 14 '23 20:12 koalo

Here is a discussion with links to all the relevant mailing discussions. Note that the current implementation is the result of several years of experience and while perhaps not immediately obvious, it is the most reasonable one. So, unless there is strong support of changing it, it will remain the way it is until at least a new YANG spec is standardized.

michalvasko avatar Dec 15 '23 07:12 michalvasko