Subject: [Netconf] ietf-netconf.yang

From: Andy Bierman <[email-masked]>
Date: Sat, 11 Apr 2009 10:04:04 -0700

Hi,

Here is a new version of the YANG module for
the NETCONF protocol.  The layers other than
operations and content have been removed.
A real hack of an extension has been added
to deal with the <filter> element.

I want to check that this is in the ballpark,
before attempting to integrate the module
into 4741-bis.

Andy

module ietf-netconf {

   namespace "urn:ietf:params:xml:ns:netconf:base:1.0";

   prefix nc;

   // for the uri data type
   import ietf-inet-types { prefix inet; }

   description 
      "NETCONF Protocol 
        * Data Types
        * Error information groupings
        * RPC methods
      ";

   reference
      "Translated from RFC 4741.";

   contact
     "TBD: WG contact info here";

   revision 2009-04-11 {
     description 
       "Initial version";
   }

   // NETCONF capabilities defined as features
   feature writable-running {
       description "NETCONF :writable-running capability";
       reference "RFC 4741, section 8.2";
   }

   feature candidate {
       description "NETCONF :candidate capability";
       reference "RFC 4741, section 8.3";
   }

   feature confirmed-commit {
       description "NETCONF :confirmed-commit capability";
       reference "RFC 4741, section 8.4";
       if-feature candidate;
   }

   feature rollback-on-error {
       description "NETCONF :rollback-on-error capability";
       reference "RFC 4741, section 8.5";
   }

   feature validate {
       description "NETCONF :validate capability";
       reference "RFC 4741, section 8.6";
   }

   feature startup {
       description "NETCONF :startup capability";
       reference "RFC 4741, section 8.7";
   }

   feature url {
       description "NETCONF :url capability";
       reference "RFC 4741, section 8.8";
   }

   feature xpath {
       description "NETCONF :xpath capability";
       reference "RFC 4741, section 8.9";
   }

   extension get-filter-element-attributes {
      description
        "If this extension is present within the
         an 'anyxml' statement named 'filter', which must be
         conceptually defined within the RPC input section
         for the 'get' and 'get-config' RPC operations,
         then the following unqualified XML attribute is
         supported within the 'filter' element, within
         a 'get' or 'get-config' protocol operation:

           type : optional attribute with allowed
                  value strings 'subtree' and 'xpath'.
                  If missing, the default value is 'subtree'.

         If the xpath feature is supported, then the
         following unqualified XML attribute is
         also supported:

           select: optional attribute containing a
                   string representing an XPath expression.
                   The 'type' attribute must be equal to 'xpath'
                   if this attribute is present.";
   }

   // NETCONF Simple Types

   typedef SessionId {
     description "NETCONF Session Id";
     type uint32 {
       range "1..max"; 
     }
   }

   typedef SessionIdOrZero {
     description 
       "NETCONF Session Id or Zero to indicate none";
     type uint32; 
   }

   typedef ErrorType {
     description "NETCONF Error Type";
     type enumeration {
       enum transport;
       enum rpc;
       enum protocol;
       enum application;
     }
   }

   typedef ErrorTag {
     description "NETCONF Error Tag";
     type enumeration { 
       enum in-use;
       enum invalid-value;
       enum too-big;
       enum missing-attribute;
       enum bad-attribute;
       enum unknown-attribute;
       enum missing-element;
       enum bad-element;
       enum unknown-element;
       enum unknown-namespace;
       enum access-denied;
       enum lock-denied;
       enum resource-denied;
       enum rollback-failed;
       enum data-exists;
       enum data-missing;
       enum operation-not-supported;
       enum operation-failed;
       enum partial-operation;
     }
   }

   typedef ErrorSeverity {
     description "NETCONF Error Severity";
     type enumeration { 
       enum error;
       enum warning;
     }
   }

   typedef TestOptionType {
     description 
       "NETCONF 'test-option' Element Content.
        This is extended with the test-only enumeration.
        The 'set' option has no real effect since
        the entire PDU is always validated before any
        of it is applied (always test-then-set).";
     type enumeration {
       enum test-then-set;
       enum set;
       //  enum test-only;   !!!! not part of the standard yet
     }
     default "set";
   }

   typedef ErrorOptionType {
     description "NETCONF 'error-option' Element Content";
     type enumeration { 
       enum stop-on-error;
       enum continue-on-error;
       enum rollback-on-error;
     }
     default "stop-on-error";
   }

   typedef EditOperationType {
     description "NETCONF 'operation' Attribute Content";
     type enumeration { 
       enum merge;
       enum replace;
       enum create;
       enum delete;
     }
     default "merge";
   }

   typedef DefaultOperationType {
     description "NETCONF 'default-operation' Element Content";
     type enumeration { 
       enum merge;
       enum replace;
       enum none;
     }
     default "merge";
   }

   typedef ConfirmTimeoutType {
     description 
       "NETCONF 'confirm-timeout' Element Content";
     type uint32 { 
       range "1..max";
     }
     units "seconds";
     default "600";   // 10 minutes
   }

   typedef ConfigURIType {
     type inet:uri;
   }

   grouping ErrorInfoContent {
     // not actually used within this module
     description 
       "NETCONF standard 'error-info' Element Content;";

     leaf-list bad-attribute {
       description
         "Name of the missing or invalid XSD attribute.
          Used with missing-attribute, bad-attribute, and
          unknown-attribute error-tag values.";
       type   string;           // should be xs:QName
       config false;
     }

     leaf-list bad-element {
       description
         "Name of the element that contains (or should contain)
          an invalid XSD attribute when used with missing-attribute,
          bad-attribute, unknown-attribute, error-tag values.
          Name of an invalid or missing element when used with
          then missing-element, bad-element, unknown-element,
          and unknown-namespace error-tag values.";
       type   instance-identifier;        // xs:QName is wrong
       config false;
     }

     leaf-list ok-element {
       description 
         "Identifies an element in the data model
          for which the requested operation has been completed
          for that node and all its child nodes.  This element
          can appear zero or more times in the 'error-info'
          container.  Used with the partial-operation error-tag
          value.";
       type   instance-identifier;         // xs:QName is wrong
       config false;
     }

     leaf-list err-element {
       description
         "Identifies an element in the data model
          for which the requested operation has failed for that
          node and all its child nodes.  This element
          can appear zero or more times in the 'error-info'
          container.   Used with the partial-operation error-tag
          value.";
        type   instance-identifier;        // xs:QName is wrong
        config false;
      }

      leaf-list noop-element {
        description
          "Identifies an element in the data model
           for which the requested operation was not attempted for
           that node and all its child nodes.  This element
           can appear zero or more times in the <error-info>
           container.   Used with the partial-operation error-tag
           value.";
        type   string;                  // xs:QName
        config false;
      }

      leaf session-id {
       description
         "Session ID of session holding the
          requested lock, or zero to indicate a non-NETCONF
          entity holds the lock.";
        type SessionIdOrZero;
        config false;
      }
   }

   grouping RpcErrorType {
      // not actually used within this module
      description "NETCONF 'rpc-error' Element Content";

      leaf error-type {
        description 
          "Defines the conceptual layer that the error occurred.";
        type ErrorType;
        mandatory true;
      }

      leaf error-tag {
        description
          "Contains a string identifying the error condition.";
        type ErrorTag;
        mandatory true;
      }

      leaf error-severity {
        description
          "Contains a string identifying the error severity, as
           determined by the device.";
        type ErrorSeverity;
        mandatory true;
      }

      leaf error-app-tag {
        description
          "Contains a string identifying the data-model-specific
           or implementation-specific error condition, if one exists.
           This element will not be present if no appropriate 
           application error tag can be associated with a particular
           error condition.";
        type string;
      }

     leaf error-path {
       description
         "Contains the absolute XPath [2] expression identifying
          the element path to the node that is associated with the error
          being reported in a particular rpc-error element.  This element
         will not be present if no appropriate payload element can be
         associated with a particular error condition, or if the
         'bad-element' QString returned in the 'error-info' container is
         sufficient to identify the node associated with the error.  When
         the XPath expression is interpreted, the set of namespace
         declarations are those in scope on the rpc-error element,
         including the default namespace.";
       type instance-identifier;
     }

     leaf error-message {
       description
         "Contains a string suitable for human display that
          describes the error condition.  This element will not be present
          if no appropriate message is provided for a particular error
          condition.  This element SHOULD include an xml:lang attribute.";
        type string;       // really LangString 'lang' attribute allowed
      }

      anyxml error-info {
        description
          "Contains protocol- or data-model-specific error content.
           This element will not be present if no such error content is
           provided for a particular error condition.  The list in 
           RFC 4741, Appendix A, defines any mandatory error-info content 
           for each error.  After any protocol-mandated content, a 
           data model definition may mandate that certain application-layer
           error information be included in the error-info container. 
           An implementation may include additional elements to 
           provide extended and/or implementation-specific debugging 
           information.";
      }
   }

   grouping CommonConfigSourceType {
      description "Common NETCONF config parameter contents.";

      choice config-source {
        mandatory true;

        leaf candidate {
          if-feature candidate;
          description 
            "Only available if 'candidate' capability supported.";
          type empty;
        }
        leaf running {
          type empty;
        }
        leaf startup {
          if-feature startup;
          description 
            "Only available if 'startup' capability supported.";
          type empty;
        }
      }
   }

   grouping GetConfigSourceType {
      description "NETCONF config 'source' Parameter contents.";

      uses CommonConfigSourceType {
          augment config-source {
              leaf url {
                if-feature url;
                description 
                  "URL pointing to config data. Only available
                   if 'url' capability supported.";
               type ConfigURIType;
              }
          }
      }
   }

   grouping RpcOperationSourceType {
      description "NETCONF 'source' Parameter contents.";

      uses CommonConfigSourceType {
          augment config-source {
              leaf url {
                if-feature url;
                description 
                  "URL pointing to config data. Only available
                   if 'url' capability supported.";
                type ConfigURIType;
              }

              container config {
                description "Inline configuration data";
              }
          }
      }
   }

   grouping RpcOperationTargetType {
      description "NETCONF 'target' Parameter contents.";

      uses CommonConfigSourceType {
          augment config-source {
              leaf url {
                if-feature url;
                description 
                  "URL pointing to desired config data output. Only 
                   available if 'url' capability supported.";
                type ConfigURIType;
              }
          }
      }
   }

   // NETCONF Standard RPC Methods

   rpc get-config {
      description
        "Retrieve all or part of a specified configuration.";

      reference "RFC 4741, section 7.2";

      input {
        container source {
          description "Particular configuration to retrieve.";
          uses GetConfigSourceType;
        }

        anyxml filter {
          description "Subtree or Xpath filter to use.";
          nc:get-filter-element-attributes;
        }
      }

      output {
        container data {
          description 
            "Copy of the source database subset which matched
             the filter criteria (if any).";
          presence 
            "An empty data container indicates that the
             request did not produce any results.";
       }
     }
   }

   rpc edit-config {
      description
        "The 'edit-config' operation loads all or part of a specified
         configuration to the specified target configuration.  This
         operation allows the new configuration to be expressed in several
         ways, such as using a local file, a remote file, or inline.  If
         the target configuration does not exist, it will be created.  If a
         NETCONF peer supports the :url capability (Section 8.8), the <url>
         element can appear instead of the <config> parameter and should
         identify a local configuration file.

         The device analyzes the source and target configurations and
         performs the requested changes.  The target configuration is not
         necessarily replaced, as with the <copy-config> message.  Instead,
         the target configuration is changed in accordance with the
         source's data and requested operations.";

      reference "RFC 4741, section 7.2";

      input {
        container target {
          description "Particular configuration to edit.";
          // mandatory true;  
          uses RpcOperationTargetType;
        }

        leaf default-operation {
          description 
            "Default operation to apply if not explicitly set.";
          type DefaultOperationType;
        }

        leaf test-option {
          if-feature validate;
          description 
            "Test option if validate capability supported.
             The 'validate' capability must be present to set
             this object to 'test-then-set'.";
          type TestOptionType;
        }

        leaf error-option {
          description "Error recovery option.";
          type ErrorOptionType;
        }

        choice edit-content {
          mandatory true;
          container config {
            description 
              "Inline Config content: 'config' element.";
          }
          leaf url {
            if-feature url;
            description 
              "Pointer to Config content: 'url' element.";
            type ConfigURIType;
          }
        }
      }
   }

   rpc copy-config {
      description
        "Create or replace an entire configuration datastore with the
         contents of another complete configuration datastore.  If the
         target datastore exists, it is overwritten.  Otherwise, a new one
         is created, if allowed.

         If a NETCONF peer supports the :url capability (Section 8.8), the
         'url' element can appear as the <source> or <target> parameter.

         Even if it advertises the :writable-running capability, a device
         may choose not to support the <running/> configuration datastore
         as the <target> parameter of a <copy-config> operation.  A device
         may choose not to support remote-to-remote copy operations, where
         both the <source> and <target> parameters use the <url> element.

        If the source and target parameters identify the same URL or
        configuration datastore, an error MUST be returned with an error-
        tag containing invalid-value.";

      reference "RFC 4741, section 7.3";

      input {
        container target {
          description "Particular configuration to copy to.";
          // mandatory true;
          uses RpcOperationTargetType;
        }

        container source {
          description "Particular configuration to copy from.";
          // mandatory true;
          uses RpcOperationSourceType;
        }
      }
   }

   rpc delete-config {
      description
        "Delete a configuration datastore.  The 'running' configuration
         datastore cannot be deleted.

         If a NETCONF peer supports the :url capability (Section 8.8), the
         'url' element can appear as the <target> parameter.";

      reference "RFC 4741, section 7.4";

      input {
        container target {
          description "Particular configuration to delete.";
          uses RpcOperationTargetType;
        }
      }
   }

   rpc lock {
      description
        "The lock operation allows the client to lock the configuration
         system of a device.  Such locks are intended to be short-lived and
         allow a client to make a change without fear of interaction with
         other NETCONF clients, non-NETCONF clients (e.g., SNMP and command
         line interface (CLI) scripts), and human users. ...";

      reference "RFC 4741, section 7.5";

      input {
        container target {
          description "Particular configuration to lock";
          // mandatory true;
          uses RpcOperationTargetType;
        }
      }
   }

   rpc unlock {
      description
        "The unlock operation is used to release a configuration lock,
         previously obtained with the 'lock' operation.

         An unlock operation will not succeed if any of the following
         conditions are true:

         *  the specified lock is not currently active

         *  the session issuing the <unlock> operation is not the same
            session that obtained the lock

         The server MUST respond with either an <ok> element or an
         'rpc-error'.";

      reference "RFC 4741, section 7.6";

      input {
        container target {
          // mandatory true;
          description "Particular configuration to unlock.";
          uses RpcOperationTargetType;
        }
      }
   }

   rpc get {
      description
        "Retrieve running configuration and device state information.";

      reference "RFC 4741, section 7.7";

      input {
        anyxml filter {
          description
            "This parameter specifies the portion of the system
             configuration and state data to retrieve.  If this parameter is
             empty, all the device configuration and state information is
             returned.

             The filter element may optionally contain a 'type' attribute.
             This attribute indicates the type of filtering syntax used
             within the filter element.  The default filtering mechanism in
             NETCONF is referred to as subtree filtering and is described in
             Section 6.  The value 'subtree' explicitly identifies this type
             of filtering.

             If the NETCONF peer supports the :xpath capability
             (Section 8.9), the value 'xpath' may be used to indicate that
             the select attribute of the filter element contains an XPath
             expression.";
          nc:get-filter-element-attributes;
        }
      }

      output {
        container data {
          description 
            "Copy of the 'running' database subset which matched
             the filter criteria (if any).";
          presence 
            "An empty data container indicates that the
             request did not produce any results.";
        }
      }
   }

   rpc close-session {
      description
        "Request graceful termination of a NETCONF session.

         When a NETCONF server receives a <close-session> request, it will
         gracefully close the session.  The server will release any locks
         and resources associated with the session and gracefully close any
         associated connections.  Any NETCONF requests received after a
         'close-session' request will be ignored.";

      reference "RFC 4741, section 7.8";

   }

   rpc kill-session {
      description
        "Force the termination of a NETCONF session.

         When a NETCONF entity receives a <kill-session> request for an
         open session, it will abort any operations currently in process,
         release any locks and resources associated with the session, and
         close any associated connections.

         If a NETCONF server receives a <kill-session> request while
         processing a confirmed commit (Section 8.4), it must restore the
         configuration to its state before the confirmed commit was issued.

         Otherwise, the <kill-session> operation does not roll back
         configuration or other device state modifications made by the
         entity holding the lock.";

      reference "RFC 4741, section 7.9";

      input {
        leaf session-id {
          description "Particular session to kill.";
          type SessionId;
          mandatory true;
        }
      }
   }

   rpc commit {
      if-feature candidate;
      description
        "Only available if 'candidate' capability is supported.

         When a candidate configuration's content is complete, the
         configuration data can be committed, publishing the data set to
         the rest of the device and requesting the device to conform to
         the behavior described in the new configuration.

         To commit the candidate configuration as the device's new
         current configuration, use the <commit> operation.

         The 'commit' operation instructs the device to implement the
         configuration data contained in the candidate configuration.
         If the device is unable to commit all of the changes in the
         candidate configuration datastore, then the running
         configuration MUST remain unchanged.  If the device does
         succeed in committing, the running configuration MUST be
         updated with the contents of the candidate configuration.

         If the system does not have the :candidate capability, the
         'commit' operation is not available.";

      reference "RFC 4741, section 8.3.4.1";

      input {
        leaf confirmed {
          description 
            "Request a confirmed commit.  Only available if 
             'confirmed-commit' capability is supported.";
          reference "RFC 4741, section 8.4.5.1";
          type empty;
        }

        leaf confirm-timeout {
          description 
            "Request a specific timeout period for a confirmed commit
             if 'confirmed-commit' capability supported.";
          reference "RFC 4741, section 8.4.5.1";
          type ConfirmTimeoutType;
        }
      }
   }

   rpc discard-changes {
      if-feature candidate;
      description
        "Only available if 'candidate' capability is supported.

         If the client decides that the candidate configuration should not be
         committed, the 'discard-changes' operation can be used to revert the
         candidate configuration to the current running configuration.

         This operation discards any uncommitted changes by resetting the
         candidate configuration with the content of the running
         configuration.";

      reference "RFC 4741, section 8.3.4.2";

   }

   rpc validate {
      if-feature validate;
      description
         "Only available if 'validate' capability is supported.

          Validates the contents of the specified configuration.";

      reference "RFC 4741, section 8.6.4.1";

      input {
        container source {
          description "Particular configuration to validate.";
          // mandatory true;
          uses RpcOperationSourceType;
        }
      }
   }

}

---

From: Martin Bjorklund <[email-masked]>
Date: Tue, 14 Apr 2009 14:09:18 +0200 (CEST)

Hi Andy,

> before attempting to integrate the module

I have a couple of comments:

  o  You are using 'feature' to define capabilities.  The only problem
     I have with this is that according to the YANG spec, a server
     will advertise its features as part of the capability uri:

       urn:ietf:params:xml:ns:netconf:base:1.0?features=candidate,xpath

     But that's not how it is supposed to be done in this case.  So I
     wonder if it's really such a good idea to use 'feature' for
     this purpose.

  o  You define all rpc-error stuff, but with the comment:

     Is the plan to remove this?  (I think it should, since this is
     part of the RPC layer).

  o  I suggest we remove all 'CommonConfigSourceType',
     'RpcOperationSourceType' etc. and instead explicitly list each
     source / target for each operation.   I think this will be more
     clear and less error-prone.

     For example, according to the YANG module, delete-config of
     running is allowed (I know the text says otherwise).

     I think it would be fine to define one grouping per datastore,
     and then use it in all operations.

  o  Several 'mandatory true' statements are commented away - are
     there any problems with having them there?

  o  In a comment, you write that 'bad-element' should not be QName,
     as it is in the XSD.  I disagree; I think it is clear that the
     intention of 4741 is that bad-element is simply a QName, and if
     that is not enough, then 'error-path' should be used.

/martin

---

From: Andy Bierman <[email-masked]>
Date: Tue, 14 Apr 2009 07:38:27 -0700

>      wonder if it's really such a good idea to use 'feature' for

Why assume this would be done?
We can strip out all the if-feature stuff, and then
YANG becomes just as bad as XSD at describing optional
features.

Why can't a YANG module capability URI for module=ietf-netconf?features=...
be used in addition to the NETCONF base URI?

>      Is the plan to remove this?  (I think it should, since this is

I will remove it.
Are we sure these data structures will never get
reconstructed in any standard YANG data model,
and these objects will never be needed in any
sort of standard or vendor-specific monitoring extension module?

>      clear and less error-prone.

So the same 2 or 3 leafs are cut-and-pasted about a dozen times
in the module?  OK, but again, this seems just as bad as SMIv2,
and worse than XSD.

>      there any problems with having them there?

They are on containers, which are not allowed to
have the mandatory-stmt.  Most people find the ripple-up
aspect of NP containers to be very confusing, especially
when the mandatory 'bit' comes from objects derived from
a uses-stmt.

I have found that most people think mandatory-stmt
is more understandable than P/NP containers.
The comments are there to remind people that
the NP container is mandatory, but they can be
removed, since the uses-stmts are going away.
(The reader can dive into the subtree and spot the
mandatory true; statements.)

>      that is not enough, then 'error-path' should be used.

This is a bug;
The comment was only supposed to apply the
the other buggy error-info elements, but they
are getting removed anyway, so it does not matter.

Andy

---

From: Martin Bjorklund <[email-masked]>
Date: Tue, 14 Apr 2009 21:26:47 +0200 (CEST)

> YANG becomes just as bad as XSD at describing optional

In YANG, one module is reported as one capability.  When a "large"
capability has minor "subcapabilities", features are used.

If we could re-design the NETCONF module in YANG, we would probably
use features for most of the current capabilities.   But we can't do
that.

> be used in addition to the NETCONF base URI?

So a server would advertise:

   <capability>urn:...:netconf:base:1.0</capability>
   <capability>urn:...:netconf:base:1.0?features=startup</capability>

?

> sort of standard or vendor-specific monitoring extension module?

No.  But should we define them in XSD for the RPC layer definition
and also in YANG because some model might need them?

> in the module?  OK, but again, this seems just as bad as SMIv2,

I would have suggested to do the same change in the XSD, if we kept
it.

I don't think it's a good idea to define a reusable structure, and use
it in several places, and then in text describe which parts of this
structure is not used.

We should keep these groupings only if they are really reused.

/martin

---

From: Andy Bierman <[email-masked]>
Date: Tue, 14 Apr 2009 13:09:40 -0700

> use features for most of the current capabilities.   But we can't do

Well, why wasn't the partial-lock or netconf-state data models
does with features instead of capabilities?  We would not
need if-capability if people used if-feature correctly,
and left capabilities for *protocol* features only.

>    <capability>urn:...:netconf:base:1.0?features=startup</capability>

No -- I think you are right.
I think the 2 data models in progress should
be changed to use features instead of just description
statements to define the optional functionality.

> We should keep these groupings only if they are really reused.

I agree that they should be removed.
If they ever get added in a standard YANG module,
we will deal with it then.

Only the simple typedefs are left.

Andy

---

From: Martin Bjorklund <[email-masked]>
Date: Tue, 14 Apr 2009 22:15:27 +0200 (CEST)

> and left capabilities for *protocol* features only.

I would be more than happy to use features in these two data models.
The only problem is that we a normative XSD and there is no such
concept there.  Specificaly, the features=... part of the URI will
have to be described in text.

/martin

---

From: Andy Bierman <[email-masked]>
Date: Tue, 14 Apr 2009 13:45:05 -0700

> have to be described in text.

Aren't we going to have this problem for all NETCONF data models?
Or only the early YANG data models will ignore if-feature,
because a capability URI has to be used instead -- to support XSD.

Will these data models be updated after the YANG RFC is published?

Andy