Subject: [netmod] Condition in must statement

From: Gerhard Muenz <[email-masked]>
Date: Wed, 01 Jul 2009 18:30:28 +0200

Hi,

I try to specify some restrictions regarding leafref values with a must
statement in the IPFIX configuration model.

Here's the part of the YANG spec:

    list observationPoint {
      key name;
      leaf name { type string; }
      leaf observationDomainId {
        type uint32;
        mandatory true;
      }
      ...
      leaf-list selectionProcess {
        type leafref { path "/ipfix/selectionProcess/name"; }
      }
    }

    list selectionProcess {
      must "/observationPoint[selectionProcess=current().name]
        .observationDomainId.floor() =
        /observationPoint[selectionProcess=current().name]
        .observationDomainId.ceil()" {
        description "If the input of this Selection Process is an
          Observed Packet Stream originating from different
          Observation Points, the must statement ensures that all
          Observation Points belong to the same Observation Domain.";
      }
      key name;
      leaf name { type string; }
      ...
    }

The goal is that all elements of the observationPoint list referring to
one specific element of the selectionProcess list must have the same
observationDomainId value. I tried to restrict this by enforcing
observationDomainId.ceil() = observationDomainId.floor() for the
corresponding observationPoint elements.

I'm not sure if the XPath expression is correct.

Also, I would like to know which result the must statement returns if
there are no observationPoint elements at all, or if no observationPoint
is referring to the given selectionProcess element.

Is it possible to have nested "[]" in the XPath?

Because I have also something more weired in the cache list:

    list cache {
      if-feature meter;
      must "/observationPoint[
        selectionProcess=/selectionProcess[cache=current().name].name
        ].observationDomainId.floor() = /observationPoint[
        selectionProcess=/selectionProcess[cache=current().name].name
        ].observationDomainId.ceil()" {
        description "For configurations where there are no cascaded
          Selection Processes between Observation Points and this Cache,
          the must statement ensures that all Observation Points belong
          to the same Observation Domain.";
      }
      key name;
      description "Parameters of a Cache.";
      leaf name { type string; }
      ...
    }

Maybe you can help me.

Thanks,
Gerhard

---

From: Andy Bierman <[email-masked]>
Date: Wed, 01 Jul 2009 12:06:39 -0700

>       leaf name { type string; }

Aren't both of these lists under /ipfix?
These XPath expressions assume that is the case.
Not sure if this is correct, but maybe this is
what you had in mind:

   list observationPoint {
       key name;

     list selectionProcess {
       must
        "floor(/ipfix/observationPoint[name=current()/name]/observationDomainId) =
         ceil(/ipfix/observationPoint[name=current()/name]/observationDomainId)" {
         description "If the input of this Selection Process is an
           Observed Packet Stream originating from different
           Observation Points, the must statement ensures that all
           Observation Points belong to the same Observation Domain.";
       }
       key name;
       leaf name { type string; }
       ...
     }

     list cache {
       if-feature meter;
       must "floor(/ipfix/observationPoint[selectionProcess[. =
 		current()/name]]/observationDomainId) =
             ceil(/ipfix/observationPoint[selectionProcess[. =
		current()/name]]/observationDomainId)" {
         description "For configurations where there are no cascaded
           Selection Processes between Observation Points and this Cache,
           the must statement ensures that all Observation Points belong
           to the same Observation Domain.";
       }
       key name;
       description "Parameters of a Cache.";
       leaf name { type string; }
       ...
     }

> Gerhard

Andy

---

From: Martin Bjorklund <[email-masked]>
Date: Wed, 01 Jul 2009 22:50:47 +0200 (CEST)

Gerhard Muenz <[email-masked]> wrote:
> observationDomainId value.

I don't think this will be possible with XPath 1.0 in the data model
you have.  This is currently best described in text in the description
clause.

> I tried to restrict this by enforcing

But observationDomainId is an integer, so ceiling() and floor() of an
integer returns the same integer.

> I'm not sure if the XPath expression is correct.

Andy showed the correct syntax.

> is referring to the given selectionProcess element.

It returns false.

> Is it possible to have nested "[]" in the XPath?

Yes.

/martin

---

From: "Joel M. Halpern" <[email-masked]>
Date: Wed, 01 Jul 2009 17:12:14 -0400

The interesting thing in Gerhard's example is that the MUST is really 
about a set of values, not about a single value. He is trying to use 
ceiling() and floor() to reduce the set of ids to a single id.  If the 
largest and smallest id are the same, then only 1 id occurs in the list.

However, this assumes that NETMOD XPATH can produce a list of nodes 
(values) to be passed to the function.  I can't tell if this works, or not.

These examples are a very different (but quite reasonable) use of MUST. 
  They represent a constraint on a set, rather than a constraint on a 
single value.  I wonder if one could write the constraint on the main 
list be writing a MUST that says either there is no other node in the 
list with the same selection function, or any other node in the list 
with the same selection has the same domainId.  That would put the 
constraint where I suspect it belongs.

Yours,
Joel

...

---

From: Andy Bierman <[email-masked]>
Date: Wed, 01 Jul 2009 14:20:34 -0700

> integer returns the same integer.

yes -- I noticed that after I sent my email, so I wondered
if it was a float by any chance, otherwise the floor() and ceil()
functions were not what he wanted.

The following will not work because it just checks if there
is at least one entry (among all the entries with the same name)
that hast the same observationDomainId as the first entry.
(According to my understanding of XPath sec. 3.4)

     list selectionProcess {
       must
        "/ipfix/observationPoint[name=current()/name]/observationDomainId =
         /ipfix/observationPoint[1]/observationDomainId" {
         description "If the input of this Selection Process is an
           Observed Packet Stream originating from different
           Observation Points, the must statement ensures that all
           Observation Points belong to the same Observation Domain.";
       }
       key name;
       leaf name { type string; }
       ...
     }

     list cache {
       if-feature meter;
       must "/ipfix/observationPoint[selectionProcess[. =
 		current()/name]]/observationDomainId =
             /ipfix/observationPoint[selectionProcess[1]]/observationDomainId" {
         description "For configurations where there are no cascaded
           Selection Processes between Observation Points and this Cache,
           the must statement ensures that all Observation Points belong
           to the same Observation Domain.";
       }
       key name;
       description "Parameters of a Cache.";
       leaf name { type string; }
       ...
     }

Andy

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

---

From: Martin Bjorklund <[email-masked]>
Date: Thu, 02 Jul 2009 00:25:51 +0200 (CEST)

"Joel M. Halpern" <[email-masked]> wrote:
> The interesting thing in Gerhard's example is that the MUST is really about a
> set of values, not about a single value. He is trying to use ceiling() and
> floor() to reduce the set of ids to a single id.  If the largest and smallest
> id are the same, then only 1 id occurs in the list.

But that's not how these functions work.  The in-parameter is a
number, and in this example it is a nodeset.  So the nodeset gets
converted to a string (i.e. the first node's string value is used),
which is then converted to a number.

> However, this assumes that NETMOD XPATH can produce a list of nodes (values) to
> be passed to the function.  I can't tell if this works, or not.

NETMOD uses normal XPath 1.0.

> These examples are a very different (but quite reasonable) use of MUST. They
> represent a constraint on a set, rather than a constraint on a single value.  I
> wonder if one could write the constraint on the main list be writing a MUST
> that says either there is no other node in the list with the same selection
> function, or any other node in the list with the same selection has the same
> domainId.  That would put the constraint where I suspect it belongs.

I think that this expression will work:

  list selectionProcess {
    must
      "count(/ipfix/observationPoint[selectionProcess=current()/name]) =
       count(/ipfix/observationPoint
               [selectionProcess=current()/name]
               [observationDomainId=/ipfix/observationPoint
                                       [selectionProcess=current()/name][1]/
                                           observationDomainId])";

It's pretty difficult to indent and read, but it says that:

   the number of observationPoint entries with a reference to this
     selectionProcess
   MUST equal
   the number of observationPoint entries with a reference to this
     selectionProcess, which has the same observationDomainId as the
     first of them

/martin

---

From: WashamFan <[email-masked]>
Date: Thu, 02 Jul 2009 10:09:39 +0800

Hi,

>                                         [selectionProcess=current()/name][1]/

I think there might be an alternative which looks more straight:

   list selectionProcess {
     must
       "max(
/ipfix/observationPoint[selectionProcess=current()/name]/observationDomainId
             )= min(
/ipfix/observationPoint[selectionProcess=current()/name]/observationDomainId
             )
       "

washam

---

From: Martin Bjorklund <[email-masked]>
Date: Thu, 02 Jul 2009 08:20:00 +0200 (CEST)

Hi,

> /ipfix/observationPoint[selectionProcess=current()/name]/observationDomainId

This doesn't work, because there are no 'max' and 'min' functions in
the XPath 1.0 Core Function Library.

/martin

---

From: Gerhard Muenz <[email-masked]>
Date: Thu, 02 Jul 2009 15:00:01 +0200

Dear all,

Thank you very much for your feedback.

> which is then converted to a number.

Yes, I misunderstood the ceil() and floor() functions.

>      selectionProcess, which has the same observationDomainId as the

Great, thanks a lot. That should work.

And it seems to be robust against non-existing observationPoints, right?
Then, both count() should return zero.

I'll try to adopt this scheme for the second must condition as well.

Are there tools that are able to validate an XML document against these
must rules?

Regards,
Gerhard

---

From: Martin Bjorklund <[email-masked]>
Date: Thu, 02 Jul 2009 15:38:50 +0200 (CEST)

Yes.

> Are there tools that are able to validate an XML document against these

Ladislav works on the DSDL mapping in pyang.  You can use pyang to
generate schemas which then can be used to validate instance
documents.  I'm not sure if it handles must expressions yet.

/martin

---

From: Andy Bierman <[email-masked]>
Date: Thu, 02 Jul 2009 07:26:32 -0700

> Are there tools that are able to validate an XML document against these

if, by XML document, you mean NETCONF PDU, then yes,
although beta-level.

I think you could run xsltproc against dummy config files,
using a simple transform to see if the expression matched anything.
I have some test scripts somewhere for checking <get> 'select' strings
against an instance document, if you need examples.

Andy

---

From: Gerhard Muenz <[email-masked]>
Date: Thu, 02 Jul 2009 18:53:27 +0200

Dear Andy,

> against an instance document, if you need examples.

At the moment, I use pyang to generate an xsd which I use to validate my
NETCONF PDU examples. must statements do not seem to be validated with
this method.

If you had a better tool or an XSLT file for xsltproc in order to do a
more thorough validation of my configuration examples, I would
appreciate if you could pass them to me.

Thanks,
Gerhard

---

From: Ladislav Lhotka <[email-masked]>
Date: Thu, 02 Jul 2009 19:27:12 +0200

Hi,

the following should work:

must
    "not(/ipfix/observationPoint[selectionProcess=current()/name]
    /observationDomainId[1] !=
    /ipfix/observationPoint[selectionProcess=current()/name]
    /observationDomainId)"

(none of the selected nodes may differ from the first one)

Lada

-- 
Ladislav Lhotka, CESNET
PGP Key ID: E74E8C0C

---

From: Ladislav Lhotka <[email-masked]>
Date: Thu, 02 Jul 2009 19:38:55 +0200

> documents.  I'm not sure if it handles must expressions yet.

Yes, it does, it maps must expressions to Schematron asserts, except
that the missing default namespace prefixes have to be added manually
(sigh). By coincidence, just today I wrote a function which adds the
necessary prefixes, so must expressions should be fully supported soon.

The only remaining problem is the mapping of constraints imposed by
instance-identifier type.

Lada
 
-- 
Ladislav Lhotka, CESNET
PGP Key ID: E74E8C0C

---

From: Gerhard Muenz <[email-masked]>
Date: Thu, 02 Jul 2009 20:33:41 +0200

Hi Lada,

Thanks, this is even more simple.

Gerhard

Ladislav Lhotka wrote:
> Martin Bjorklund píše v C(t 02. 07. 2009 v 08:20 +0200:
>> Hi,
>>

-- 
Dipl.-Ing. Gerhard Münz
Chair for Network Architectures and Services (I8)
Department of Informatics
Technische Universität München
Boltzmannstr. 3, 85748 Garching bei München, Germany
Phone:  +49 89 289-18008       Fax: +49 89 289-18033
E-mail: [email-masked]    WWW: http://www.net.in.tum.de/~muenz