Skip to content

must evaluated in empty container #2140

Closed

Description

@koalo

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".)

Activity

  1. jktjkt commented on Dec 11, 2023

    @jktjkt
    Contributor

    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.

  2. koalo commented on Dec 11, 2023

    @koalo
    Author
  3. michalvasko commented on Dec 14, 2023

    @michalvasko
    Member

    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.

  4. koalo commented on Dec 14, 2023

    @koalo
    Author

    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?

  5. michalvasko commented on Dec 15, 2023

    @michalvasko
    Member

    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.

  6. koalo commented on Jun 18, 2024

    @koalo
    Author

    Took some time for us to understand all the details, but now we fully agree that libyang is correct in this regard and the standard needs to be fixed.
    See https://github.com/Linutronix/yang-validation/blob/main/qcw/README.md for details.

    I opened #2256 that is a only remotely related and close this issue.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    is:questionIssue is actually a question.

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions