RFC6020 - YANG语言标准中文

Java 同时被 2 个专栏收录
43 篇文章 0 订阅
12 篇文章 0 订阅

YANG - A Data Modeling Language for the Network Configuration Protocol (NETCONF)

该标准脱胎于草案draft-ietf-netmod-yang,该草案从2008年5月开始,先后经历了13个草案版本,最终于2010年8月成为建议标准(Proposed Standard)。本文档的翻译时间开始于2016年5月12日。

本文档有勘误表存在。

摘要

YANG是一种数据建模语言,被用来为NETCONF,NETCONF远程过程调用,NETCONF Notification操作的配置和状态数据进行建模。

本文档状态

This is an Internet Standards Track document.

This document is a product of the Internet Engineering Task Force 
(IETF). It represents the consensus of the IETF community. It has 
received public review and has been approved for publication by the 
Internet Engineering Steering Group (IESG). Further information on 
Internet Standards is available in Section 2 of RFC 5741.

Information about the current status of this document, any errata, 
and how to provide feedback on it may be obtained at 
http://www.rfc-editor.org/info/rfc6020.

版权信息

Copyright (c) 2010 IETF Trust and the persons identified as the 
document authors. All rights reserved.

This document is subject to BCP 78 and the IETF Trust’s Legal 
Provisions Relating to IETF Documents 
(http://trustee.ietf.org/license-info) in effect on the date of 
publication of this document. Please review these documents 
carefully, as they describe your rights and restrictions with respect 
to this document. Code Components extracted from this document must 
include Simplified BSD License text as described in Section 4.e of 
the Trust Legal Provisions and are provided without warranty as 
described in the Simplified BSD License.

This document may contain material from IETF Documents or IETF 
Contributions published or made publicly available before November 
10, 2008. The person(s) controlling the copyright in some of this 
material may not have granted the IETF Trust the right to allow 
modifications of such material outside the IETF Standards Process. 
Without obtaining an adequate license from the person(s) controlling 
the copyright in such materials, this document may not be modified 
outside the IETF Standards Process, and derivative works of it may 
not be created outside the IETF Standards Process, except to format 
it for publication as an RFC or to translate it into languages other 
than English.

1. 介绍

YANG是一种数据建模语言,被用来为NETCONF,NETCONF远程过程调用,NETCONF Notification操作的配置和状态数据进行建模。

本文档描述了YANG语言的语法和语义,在一个YANG module中定义的数据模型如何以XML的形式表示,NETCONF如何操作数据。

2. 关键词

The keywords “MUST”, “MUST NOT”, “REQUIRED”, “SHALL”, “SHALL NOT”, 
“SHOULD”, “SHOULD NOT”, “RECOMMENDED”, “NOT RECOMMENDED”, “MAY”, and 
“OPTIONAL” in this document are to be interpreted as described in BCP 
14, [RFC2119].

3. 术语

  • anyxml —— 一种数据节点,能够包含未知的XML格式的数据块。
  • augment —— 向之前定义的schema node增加新的schema nodes。
  • base type —— 可以被用来继承的数据类型,可以使built-in类型,也可以是派生的类型。
  • built-in type —— YANG语言定义的YANG数据类型,比如uint32 或者 string
  • choice —— 一个schema node,其值是多个可选项中的一个。
  • configuration data —— 可写入的数据的集合,被用来转变系统的状态【RFC4741】。
  • conformance(一致性) —— 一种评估实际上设备在多大程度上服从数据模型的方法。
  • container —— 一种内建的数据节点,在data tree中,最多只能有一个实例存在。一个container没有值,不过会包含一些子节点。
  • data definition statement —— 一种定义新的数据节点的声明(statement)。可以是container,leaf,leaf-list,list,choice,case,augment,uses,以及anyxml中的一个。
  • data model —— 一种表述数据如何展现和访问的数据模型。
  • data node(数据节点) —— schema tree中的一个节点,能够在data tree中实例化。可以是container,leaf,leaf-list,list,以及anyxml中的一个。
  • data tree —— 由一个设备上的配置和状态数据实例化的树。
  • derived type(派生类型) —— 一种从内建数据类型,或者其他派生类型中派生出来的类型。
  • device deviation(设备偏差) —— 如实反映设备在实现YANG模块时候的失败情况。
  • extension —— 使用非YANG语义声明的扩展。扩展声明定义了新的statement表示这些语义。
  • feature —— 一种可选的能够标记模型的某一部分的机制。可以使用feature名作为标签,不过该标签仅仅在支持该feature的设备上才有效。
  • grouping —— 一种可重用的schema nodes的集合。该集合可能在定义处的module中被使用,也可能在包含它的modules中使用,还可能在导入它的modules中被使用。grouping声明不是一种数据定义声明,它不会在schema node中定义任何节点。
  • identifier —— 通过名字,被用来识别不同种类的YANG items。
  • instance identifier —— 在data tree中被用来标记特定的一个节点。
  • interior node —— 分层结构中,非leaf node的节点。
  • leaf —— 一种数据节点,在data tree中最多只能有一个实例存在。一个leaf节点只能有一个值,并且不能有子节点。
  • leaf-list —— 和leaf节点相似,但是定义了一集合的可唯一识别的节点,而非一个节点。其中每一个节点都有值,但是都没有子节点。
  • list —— 一种内部的数据节点,在data tree中可能会有多个实例存在。一个list没有值,但是会有一些子节点。
  • module —— 一个YANG module定义了一个具有垂直层级结构的节点集,这些节点能够被用于基于NETCONF的operations。如果有一个module的定义,以及该module依赖的其他module的定义,则这个module是自足的,以及“可编译的(compilable)”。
  • RPC —— 远程过程调用,在NETCONF协议中使用的。
  • RPC operation —— 一种特定的远程过程调用,在NETCONF协议中使用的。也被成为协议操作(protocol operation)。
  • schema node —— 在schema tree中的节点。是container,leaf,leaf-list,list,choice,case,rpc,input,output,notification,以及anyxml中的一种。
  • schema tree —— module中的特定垂直结构定义(The definition hierarchy specified within a module.)。
  • state data(状态数据) —— 系统中的配置数据之外的其他额外数据,比如只读的状态信息,数据统计信息【RFC4741】。
  • submodule —— 一种局部的module定义。submodule为所在的module提供了derived types,groupings,data nodes,RPCs,以及notifications。一个YANG module可以由多个submodules组成。
  • top-level data node —— 一个数据节点,在该节点和module/submodule声明之间,没有其他的数据节点存在。
  • uses —— 这个“uses”声明被用来实例化在grouping声明中定义的schema nodes。这些实例化的节点可能会被扩展以满足特定的需求。

搞不明白feature的具体用法。不知道data tree和schema tree的区别。

3.1 Mandatory Nodes(必须出现的节点)

一个mandatory node是以下中的:

  • “mandatory”声明为“true”的一个leaf,choice,或者anyxml节点。
  • “min-elements”声明为大于0的数的一个list,或者leaf-list节点。
  • 没有“presence”声明的container节点,它里面至少要包含一个mandatory node的子节点。

4. YANG总览

4.1 功能总览

YANG是一种被用来为NETCONF协议建模的语言。一个YANG module定义了具有垂直结构的数据,这些数据可以被用做基于NETCONF的operations,比如configuration,state date,RPCs,以及notifications。它使得NETCONF的client和server之间能有完整的数据描述。

YANG建模得到的数据具备树形结构。其中每一个节点都有一个名字,都有一个值或者一些子节点。YANG为这些节点,以及节点之间的交互提供明确清晰的描述。

YANG使用modules和submodule进行数据建模。一个module能够从其他外部的modules中导入数据,也可以从submodules中包含数据。YANG定义的垂直结构可以扩展,使得一个module能够增加数据节点给另一个module。这种扩展是有条件的,只有特定条件满足,新的数据节点才会出现。

YANG模型还能描述数据之上增加的约束,基于垂直结构中其他节点的出现与否,值为多少等等来限制一些节点的出现与赋值。这些约束可以被client或者server强制执行。不过如果要使得内容有效,MUST 双方都要遵守特定的约定。

YANG定义了一系列的内建数据类型,也有定义新数据类型的类型命名机制。派生数据类型可以通过像range,pattern这样的声明限制其原生数据类型的取值范围,这样的声明在client或者server端都可以执行。它们还能为派生数据类型定义常用用法,比如定义一个string-based类型,包含主机名。

YANG允许对可重用的grouping中节点的定义。这些groupings中的实例能够通过特定的增强以满足特殊的需求。派生类型以及groupings能够定义在一个module或者submodule中,能够被本地,其他module/submodule导入和使用。

YANG的垂直数据结构包括了对list的定义。list中包含的每一项都有唯一的key以区分彼此。这样的lists有可能被用户自定义排序或者由系统进行默认排序。对于用户自定义排序的lists来说,operations是为了对列表项进行排序定义的。

YANG modules可以被转换为等价的XML格式,称为YANG Independent Notation(YIN)(Section 11),这使得相关的应用可以通过XML解析器或者XSLT脚本进行操作。从YANG到YIN的转换是无损的,因此也可以从YIN格式转换为YANG文件。

YANG试图在高层的数据建模和底层的比特数据编码(bits-on-the-wire encoding)之间追求平衡。YANG module的reader可以查看数据模型的高层视图,同时也能理解在NETCONF operations中,这些数据如何编码。

YANG是一种可扩展语言,允许标准制定者,设备商,以及个人定义新的声明(statement)。声明的语法使得这些扩展能够以一种自然的方式和标准的YANG 声明共存,同时使得reader能够有效得认知这些新扩展。

YANG resists the tendency to solve all possible problems, limiting the problem space to allow expression of NETCONF data models, not arbitrary XML documents or arbitrary data models. The data models described by YANG are designed to be easily operated upon by NETCONF operations.

为了扩大使用范围,YANG和SNMP协议的SMIv2(Structure of Management Information,RFC2578RFC2579)保持了兼容。基于SMIv2的MIB modules能够以只读的方式自动转换为YANG modules。然而,YANG并不关心如何从YANG转换为SMIv2。

和NETCONF相似,YANG致力于和设备本身自带的管理机制进行平滑集成。这就使得需要利用设备当前的访问控制机制去保护/暴露数据模型的相应元素。

4.2 语言总览

本小节引入了YANG语言中的一些重要结构,这些在后面的章节中,对于理解语言细节能够提供一些帮助。这种方法解决了难以理解的相互联系的YANG概念和声明的复杂关系问题。关于YANG的声明(statement)和语法(syntax)的细节描述可见Section 7。

4.2.1 Modules和Submodules

一个module包含了三种类型的声明:

  • module-header statement(模块头声明) —— 描述了该module,给出了module相关的信息。
  • revision statement(版本声明)—— 描述了该module的历史信息。
  • definition statement(定义声明) —— 定义了数据模型的内容部分。

一个NETCONF Server可能会实现多个modules,拥有相同设备数据的多个视图,或者互不相交的多个子集的多个视图。这种情况下,Server可能会选择仅仅实现定义了所有可用数据的一个module。(A NETCONF server may implement a number of modules, allowing multiple views of the same data, or multiple views of disjoint subsections of the device’s data. Alternatively, the server may implement only one module that defines all available data.)

根据需求,一个module可以被分为多个submodules。而对外来说,依然是单个module,无论内部拥有多少个submodules。

“include”声明允许一个module或者submodule引用submodules中定义的数据;“import”声明允许引用其他modules中定义的数据。

4.2.2 数据建模基础(Data Modeling Basics)

YANG定义了四种用于数据建模的节点类型。在下面的每一个小节中,都有例子展示了YANG语法以及相应的NETCONF XML表达。

4.2.2.1 Leaf Nodes

一个leaf node包含了像integer或者string这样的简单数据。它有且仅有一个特定类型的值,并且没有子节点。

YANG 示例:

   leaf host-name {
       type string;
       description "Hostname for this system";
   }
  • 1
  • 2
  • 3
  • 4
  • 5

NETCONF XML 示例:

   <host-name>my.example.com</host-name>
  • 1
  • 2

“leaf”的声明可以在Section 7.6 中找到。

4.2.2.2 Leaf-List Nodes

一个leaf-list是一系列的leaf nodes,每个leaf都有特定类型的值。

YANG 示例:

 leaf-list domain-search {
     type string;
     description "List of domain names to search";
 }
  • 1
  • 2
  • 3
  • 4
  • 5

NETCONF XML 示例:

 <domain-search>high.example.com</domain-search>
 <domain-search>low.example.com</domain-search>
 <domain-search>everywhere.example.com</domain-search>
  • 1
  • 2
  • 3
  • 4

“leaf-list”的声明可以在Section 7.7 中找到。

4.2.2.3 Container Nodes

一个container node用来将相关的节点归总到一个subtree中。一个container node只有子节点,没有值。一个container可能会包含任何类型的任何数量的子节点(包括leafs,lists,leaf-lists以及containers)。

YANG 示例:

 container system {
     container login {
         leaf message {
             type string;
             description
                 "Message given at start of login session";
         }
     }
 }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

NETCONF XML 示例:

 <system>
   <login>
     <message>Good morning</message>
   </login>
 </system>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

“container”的声明可以在Section 7.5 中找到。

4.2.2.4 List Nodes

一个List定义了一系列的列表项(list entries)。每个列表项都像是一个structure或者一个record instance,通过名为“key”的leaf的值唯一确定。一个list能定义多种key leafs,能够包含任意类型的任意数目的子节点(包括leafs,lists,containers)。

YANG 示例:

 list user {
     key "name";
     leaf name {
         type string;
     }
     leaf full-name {
         type string;
     }
     leaf class {
         type string;
     }
 }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

NETCONF XML 示例:

 <user>
   <name>glocks</name>
   <full-name>Goldie Locks</full-name>
   <class>intruder</class>
 </user>
 <user>
   <name>snowey</name>
   <full-name>Snow White</full-name>
   <class>free-loader</class>
 </user>
 <user>
   <name>rzell</name>
   <full-name>Rapun Zell</full-name>
   <class>tower</class>
 </user>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

“list”的声明可以在Section 7.8 中找到。

4.2.2.5 Module示例

上述的那些声明组合起来能够定义一个简单的module:

 // Contents of "acme-system.yang"
 module acme-system {
     namespace "http://acme.example.com/system";
     prefix "acme";

     organization "ACME Inc.";
     contact "joe@acme.example.com";
     description
         "The module for entities implementing the ACME system.";

     revision 2007-06-09 {
         description "Initial revision.";
     }

     container system {
         leaf host-name {
             type string;
             description "Hostname for this system";
         }

         leaf-list domain-search {
             type string;
             description "List of domain names to search";
         }

         container login {
             leaf message {
                 type string;
                 description
                     "Message given at start of login session";
             }

             list user {
                 key "name";
                 leaf name {
                     type string;
                 }
                 leaf full-name {
                     type string;
                 }
                 leaf class {
                     type string;
                 }
             }
         }
     }
 }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48

4.2.3 State Data

YANG 能够通过“config”声明对state data和configuration data进行建模。当一个节点打上了“config false”的标签,它的子结构就打上了state data的标签,会通过NETCONF的操作,而不是操作。作为其父节点的containers,lists,以及key leafs也会上报,以给这个state data明确的上下文环境。

不清楚为什么还会有key leafs。

在下面的例子中,每个interface都定义了两个leafs,一个是configured speed(配置速率),另一个是observed speed(观察速率)。观察速率是不可配置的,所以它能通过NETCONF的操作获取,但是不能通过操作获取,也不能通过操作操作。

 list interface {
     key "name";

     leaf name {
         type string;
     }
     leaf speed {
         type enumeration {
             enum 10m;
             enum 100m;
             enum auto;
         }
     }
     leaf observed-speed {
         type uint32;
         config false;
     }
 }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19

4.2.4 Built-in Types

和一些编程语言类似,YANG也有一系列的内置类型。下面的表格就总结了在Section 9描述的内置数据类型:

   +---------------------+-------------------------------------+
   | Name                | Description                         |
   +---------------------+-------------------------------------+
   | binary              | Any binary data                     |
   | bits                | A set of bits or flags              |
   | boolean             | "true" or "false"                   |
   | decimal64           | 64-bit signed decimal number        |
   | empty               | A leaf that does not have any value |
   | enumeration         | Enumerated strings                  |
   | identityref         | A reference to an abstract identity |
   | instance-identifier | References a data tree node         |
   | int8                | 8-bit signed integer                |
   | int16               | 16-bit signed integer               |
   | int32               | 32-bit signed integer               |
   | int64               | 64-bit signed integer               |
   | leafref             | A reference to a leaf instance      |
   | string              | Human-readable string               |
   | uint8               | 8-bit unsigned integer              |
   | uint16              | 16-bit unsigned integer             |
   | uint32              | 32-bit unsigned integer             |
   | uint64              | 64-bit unsigned integer             |
   | union               | Choice of member types              |
   +---------------------+-------------------------------------+
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24

“type”的声明可以在Section 7.4 中找到。

4.2.5 Derived Types(typedef)

YANG能够使用“typedef”声明从基本类型中定义派生类型。一个基本类型可以是内置类型或者派生类型。

YANG 示例:

 typedef percent {
     type uint8 {
         range "0 .. 100";
     }
     description "Percentage";
 }

 leaf completed {
     type percent;
 }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

NETCONF XML 示例:

 <completed>20</completed>
  • 1
  • 2

“typedef”的声明可以在Section 7.3 中找到。

4.2.6 可重用的节点组(grouping)

可以使用“grouping”声明将一组节点放到可重用的集合中去。一个grouping定义了节点的集合,该集合可以使用“uses”声明实例化:

YANG 示例: 
grouping target { 
leaf address { 
type inet:ip-address; 
description “Target IP address”; 

leaf port { 
type inet:port-number; 
description “Target port number”; 

}

 container peer {
     container destination {
         uses target;
     }
 }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

NETCONF XML 示例:

 <peer>
   <destination>
     <address>192.0.2.1</address>
     <port>830</port>
   </destination>
 </peer>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

grouping可以根据它被调用时候的用途进行优化,重写特定的声明来覆盖原来grouping的定义。在下面的例子中,description被重定义了:

 container connection {
     container source {
         uses target {
             refine "address" {
                 description "Source IP address";
             }
             refine "port" {
                 description "Source port number";
             }
         }
     }
     container destination {
         uses target {
             refine "address" {
                 description "Destination IP address";
             }
             refine "port" {
                 description "Destination port number";
             }
         }
     }
 }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23

“grouping”的声明可以在Section 7.11 中找到。

4.2.7 choice

YANG能够使用“choice”和“case”声明分离互不相容,不能同时出现的节点。“choice”声明包含了多个“case”声明,定义了不能同时出现的schema nodes的集合。每个“case”声明都可能包含多个节点,但是每个节点都应该只在一个“case”中出现。

当一个case元素被创建,其他所有cases的元素都会被隐式删除。设备要强制执行这个约束,以防止出现配置的不协调。

“choice”和“case”节点只会出现在schema tree中,不能出现在data tree或者NETCONF message

YANG 示例:

 container food {
   choice snack {
       case sports-arena {
           leaf pretzel {
               type empty;
           }
           leaf beer {
               type empty;
           }
       }
       case late-night {
           leaf chocolate {
               type enumeration {
                   enum dark;
                   enum milk;
                   enum first-available;
               }
           }
       }
   }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22

NETCONF XML 示例:

 <food>
   <pretzel/>
   <beer/>
 </food>
  • 1
  • 2
  • 3
  • 4
  • 5

“choice”的声明可以在Section 7.9 中找到。

4.2.8 扩展数据模型(augment)

YANG允许一个模块将额外的节点插入到数据模型中,包括当前的module(以及它的submodule)或者一个外部的module。这一点是很有用的,比如对于设备商来说,需要在标准数据模型中插入设备商指定的参数。

“augment”声明定义了在数据模型树形结构中,新的节点插入的位置。“when”声明了新节点生效的时间。

YANG 示例:

 augment /system/login/user {
     when "class != 'wheel'";
     leaf uid {
         type uint16 {
             range "1000 .. 30000";
         }
     }
 }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

这个例子定义了一个“uid”的leaf node,该node仅在user的class不等于wheel的时候才有效。

如果一个module增强了另一个module,则数据的XML表示将会影响增强它的module的前缀。比如,如果上一个例子的augment是放在一个“other”前缀的module中,则其XML看起来应该是这样的:

NETCONF XML 示例:

 <user>
   <name>alicew</name>
   <full-name>Alice N. Wonderland</full-name>
   <class>drop-out</class>
   <other:uid>1024</other:uid>
 </user>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

“augment”的声明可以在Section 7.15中找到。

4.2.9 RPC定义

YANG也能定义NETCONF中的RPCs。RPC中的operations’ name,输入参数,和输出参数都可以通过YANG的数据定义声明进行建模。

YANG 示例:

 rpc activate-software-image {
     input {
         leaf image-name {
             type string;
         }
     }
     output {
         leaf status {
             type string;
         }
     }
 }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

NETCONF XML 示例:

 <rpc message-id="101"
      xmlns="urn:ietf:params:xml:ns:netconf:base:1.0">
   <activate-software-image xmlns="http://acme.example.com/system">
     <image-name>acmefw-2.3</image-name>
  </activate-software-image>
 </rpc>

 <rpc-reply message-id="101"
            xmlns="urn:ietf:params:xml:ns:netconf:base:1.0">
   <status xmlns="http://acme.example.com/system">
     The image acmefw-2.3 is being installed.
   </status>
 </rpc-reply>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

“rpc”的声明可以在Section 7.13中找到。

4.2.10 Notification定义。

YANG的notification定义和NETCONF适配。YANG的数据定义声明被用来为notification的内容建模。

YANG Example:

 notification link-failure {
     description "A link failure has been detected";
     leaf if-name {
         type leafref {
             path "/interface/name";
         }
     }
     leaf if-admin-status {
         type admin-status;
     }
     leaf if-oper-status {
         type oper-status;
     }
 }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

NETCONF XML Example:

 <notification
     xmlns="urn:ietf:params:netconf:capability:notification:1.0">
   <eventTime>2007-09-01T10:00:00Z</eventTime>
   <link-failure xmlns="http://acme.example.com/system">
     <if-name>so-1/2/3.0</if-name>
     <if-admin-status>up</if-admin-status>
     <if-oper-status>down</if-oper-status>
   </link-failure>
 </notification>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

notification和rpc都是NETCONF中的定义,虽然大概明白什么意思,但是具体就不清楚了,需要去NETCONF的标准中去查看定义。

“notification”的声明可以在Section 7.14中找到。

5. 语言概念

5.1 modules和submodules

在YANG语言中,module是基本单位。每个module都定义一个数据模型。一个module能够定义一个完整的模型,或者对当前数据模型做额外扩展。

submodules是module的一部分,能够为一个module提供相关定义。一个module能包含任意数量的submodules,但是每个submodule只能属于一个module。

所有标准的modules和submodules的名字都 MUST 是唯一的。我们 RECOMMEND 企业级modules的开发者选择和标准模型以及其他企业modules不冲突的名字,比如说,使用企业或组织名字作为module名字的前缀。

一个module使用“include”声明包含它的submodules,使用“import”声明引入外部的modules。相似的,一个submodule会使用“include”声明引用同一个module中的其他submodules,使用“import”声明引用其他modules。一个module或submodule MUST NOT 包含其他modules中的submodules,一个submodule MUST NOT 导入它自己所在的module。

导入(import)和包含(include)声明使用如下:

  • 如果一个module或submodule需要引用来自外部的module,外部的module MUST 被imported。
  • 如果一个module需要引用其内部的某个submodule,这个module MUST include这个submodule。
  • 如果一个submodule需要引用同一个module内部的其他submodule,则这个submodule MUST include另一个submodule。

在modules/submodules的imports和includes中,MUST NOT 形成环形调用链。比如,如果submodule “a”包含了submodule “b”,则“b”就不能包含submodule “a”了。

当在一个外部module的定义被引用时, MUST 使用局部定义的前缀,后面跟着冒号“:”,然后是具体使用的外部module的id。对本地module定义的引用可以使用前缀,也可以不使用。由于built-in类型不属于任何module,所以对built-in类型的引用不能使用任何前缀。

5.1.1 Import and Include by Revision

随着时间的推移,已经发布的modules会慢慢演进出新的版本。为了支持这样的正常演进过程,modules在被其他module import时需要使用其revisions。当一个module完成时,它会基于当前时间使用可用的带有特定revisions的其他modules。如果后来,被imported的modules更新了,该module不会受到影响。当这个module的作者准备将“import”的module更新到最新版本,只需要修改“revision”字段就可以了。

对于submodule来说,方案相似不过更加简单。一个module或者submodule,在包含其他的submodule的时候都要指定被包含submodules的revision。如果一个submodule改变了,任何包含它的其他module或者submodules都需要被更新。

比如,module “b” 导入了module “a”:

 module a {
     revision 2008-01-01 { ... }
     grouping a {
         leaf eh { .... }
     }
 }

 module b {
     import a {
         prefix p;
         revision-date 2008-01-01;
     }

     container bee {
         uses p:a;
     }
 }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18

当module “a” 的作者发布了一个新的revision,新版本的更改可能不为“b”所接受。如果“b”接受,则需要更新其导入“a”的import语句中的revision版本。

5.1.2 Module分层

YANG能支持数据模型的多层次划分,在该划分中,数据可能有不止一个top-level(顶级)的节点。拥有多个top-level节点的数据模型有时候是更加方便的。

NETCONF协议能够在<config><data>元素中包含任何XML内容作为载荷。YANG模型中的顶级结点在上述两种元素中以任意顺序,作为子节点存在。在这些子节点中,要保证NETCONF消息已经封装成正确的XML格式了。

比如:

 module my-config {
     namespace "http://example.com/schema/config";
     prefix "co";

     container system { ... }
     container routing { ... }
 }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

在NETCONF中被封装为:

 <rpc message-id="101"
      xmlns="urn:ietf:params:xml:ns:netconf:base:1.0"
      xmlns:nc="urn:ietf:params:xml:ns:netconf:base:1.0">
   <edit-config>
     <target>
       <running/>
     </target>
     <config>
       <system xmlns="http://example.com/schema/config">
         <!-- system data here -->
       </system>
       <routing xmlns="http://example.com/schema/config">
         <!-- routing data here -->
       </routing>
     </config>
   </edit-config>
 </rpc>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18

除了YANG定义之外的rpc,message-id什么的都搞不懂。还需要看一下NETCONF啊。

5.2 文件格式

YANG modules和submodules通常都会以文件的形式存储,每个module或者submodule一个文件。文件的命名格式 SHOULD 是这种格式:

module-or-submodule-name ['@' revision-date] ( '.yang' / '.yin' )
  • 1
  • 2

YANG编译器能够通过文件名找到导入的modules和包含的submodules。当使用YANG语言定义modules的时候,出于性能和manageability的考虑,编译器可能会分别编译每一个submodules。在submodules的编译期间,errors和warnings不能被检测到。直到将submodules并入module的时候,才会发现错误和警告。

5.3 XML Namespace

所有的YANG定义都包含在YANG module中,每个YANG module都会和特定的XML namespace XML NAMES绑定,该命名空间是全局唯一的URI RFC3986。NETCONF的客户端和服务端在封装数据的时候,使用这个命名空间。

modules的Namespace发布在rfc4844中, MUST 由IANA分配,可见Section 14。

私有module的namespace分配由拥有该module的组织分配。Namespace URIs的分配必须保证不能与标准的modules冲突,不能与其他私有的modules冲突,可以在namespace中使用组织/公司名字以避免明明冲突。

“namespace”声明可以在Section 7.1.3见到。

5.3.1 YANG XML Namespace

YANG 为NETCONF的 <edit-config> 和<error-info>内容定义了XML namespace。这个namespace的名字是“urn:ietf:params:xml:ns:yang:1”。

5.4 解析Grouping,Type,和Identify名

Gouping,Type,和Identify的名字是在它们被定义的地方被解析的,而不是在它们被使用的地方被解析的。groupings, typedefs,identifies的使用者并不被强制要求导入modules或者包含submodules,以满足原始定义的引用要求。这种特性类似于传统编程语言中的静态变量作用域。

比如,如果一个module定义了一个grouping,在其中引用了一个type。当这个grouping在另一个module中被引用的时候,该type在原来的module的上下文中被解析,而不是在第二个module中被解析。如此一来就不用担心多个module共同定义同一个type时候引起的冲突问题了。

5.5. Nested Typedefs和Groupings

在很多YANG statements中,typedefs和groupings都可能出现嵌套的情况。在层级结构中,它们在语义上局限于被定义的层级(也就是说解析的时候不会波及到其他层级)。这使得types和groupings可以定义在和被使用的地方接近的地方,而不是放到层级结构的顶级。这种使用处定义的特性增强了可读性。(Typedefs and groupings may appear nested under many YANG statements, allowing these to be lexically scoped by the hierarchy under which they appear. This allows types and groupings to be defined near where they are used, rather than placing them at the top level of the hierarchy. The close proximity increases readability.

作用域(scoping)的作用使得在不同submodules定义的types可以出现命名冲突,因为它们的作用域没有交集。

最后,作用域使得module的作者能够使得他们定义的types和groupings能够只对他们的module或submodule有效,防止了其他人的重用。由于只有顶级的types和groupings能够在module/submodule外部被使用,开发者能够有更多的控制能力,控制module的哪些部分要对外开放,哪些部分要在内部保持私有。

作用域的定义 MUST NOT 覆盖更高级别的作用域的定义。当在schema层级结构中,当更高级别中已经定义了,则更低级别中不能再定义相同的“types”和“groupings”了。

对于没有前缀的type或grouping的引用,或者使用当前module名作为前缀的引用,会被解析为和type或grouping声明最匹配的结构。(A reference to an unprefixed type or grouping, or one which uses the prefix of the current module, is resolved by locating the closest matching “typedef” or “grouping” statement among the immediate substatements of each ancestor statement.

5.6 一致性

一致性(conformance)是衡量一个设备实际上与model契合的程度。通常来说,设备需要如实完全实现model的定义,这样一来上层应用才能按照model的定义来看待下面的设备。设备与model的差异会降低model的可用性,同时使得使用该model的application更加脆弱。

YANG针对一致性有三种检查机制:

  • model的基础行为检查
  • model可选特性的检查
  • 和model之间的偏差

接下来我们会挨个讨论每一种机制。

5.6.1 基础行为

model定义了NETCONF的client和server之间的constract(协议),这使得通信双方能够互相理解对方发送的模型化数据背后蕴含的语法和语义。YANG的优点就是constract的优点。

5.6.2 可选特性

在很多models中,作者会允许models中的某些部分在有一定先决条件的情况下才会出现/禁止出现。设备可以决定,是否支持model中定义的可选功能。

比如,一个syslog data model可能会选择支持本地存储日志的能力,但是model作者知道,在实际设备中,只有当这个设备有本地存储器的时候才有可能支持该功能。如果设备上没有本地存储器,则application就不能通知设备去存储日志。

YANG通过名为“feature”的结构支持这种可选特性的机制。features使得模型作者能够让设备根据实际情况有选择实现一些可选的特性。这样一来,在model中就能表现一些只有部分设备支持的特性。这些特性被包含在model的定义中,能够使得不同设备的模型尽可能保持一致性,让application能够获知哪些特性被支持,并在此基础上对设备进行操作。

一个module可以声明任意数量的features,这些特性用字符串id做识别。如果一个设备支持某个feature,则module中对应的部分对该设备来说就是可用的;反之亦然。

features是用“feature”声明定义的。如果该feature是有条件的(conditional),则需要使用“if-feature”声明。

更多细节可见Section 7.18.1

还是不太明白feature的应用实例。

5.6.3 偏差(deviations)

在理想情况下,所有的设备都应该完全实现model的定义,不会和model出现任何偏差。但是实际情况下,设备总会和model有各种各样的差异存在。为了让YANG能够支持针对实际存在的偏差的自动处理,设备上必须有一种机制能够通知applications它和model之间的偏差。

比如,一个BGP module能支持任意多的BGP peers,但是一个特定的设备可能最多只能支持16个peers。任何application发送的第17个peer的连接请求都会失败。相比较于设备用错误消息通知application,更好的解决方法是application从一开始就知道16个peers的限制,并且能够避免用户申请注定失败的第17个peer连接。

设备的deviations使用“deviation”声明,它使用在schema tree中表示一个节点的字符串作为参数。The contents of the statement details the manner in which the device implementation deviates from the contract as defined in the module.

更多细节可见Section 7.18.3

5.6.4 在消息中宣告一致性(Conformance)信息

命名空间URI MUST 作为一种能力(capability),在NETCONF的消息中向外通告,表示NETCONF服务器支持YANG module。该URI的格式 MUST 如下:

 capability-string   = namespace-uri [ parameter-list ]
 parameter-list      = "?" parameter *( "&" parameter )
 parameter           = revision-parameter /
                       module-parameter /
                       feature-parameter /
                       deviation-parameter
 revision-parameter  = "revision=" revision-date
 module-parameter    = "module=" module-name
 feature-parameter   = "features=" feature *( "," feature )
 deviation-parameter = "deviations=" deviation *( "," deviation )
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • “revision-date”表示NETCONF服务器实现的module的revision
  • “module-name”表示module的名字,如同“module”声明一样
  • “namespace-uri”表示这个module的namespace URI,如同在“namespace”声明中出现的一样
  • “feature”表示设备实现的可选的feature
  • “eviation”表示定义了设备的偏差的module的名字

在以上的参数列表中,每个参数 MUST 出现一次。

5.6.4.1 Modules

服务器通过消息通告它所支持的modules的名字。Module的namespaces是在capability字符串中作为基础URI编码的,mdule的名字被编码为“module”参数放到基础URI中。

一个服务器 MUST 声明它所实现的所有modules的所有revisions。

比如,下面的消息声明了一个module “syslog”。

    <hello xmlns="urn:ietf:params:xml:ns:netconf:base:1.0">
      <capability>
        http://example.com/syslog?module=syslog&amp;revision=2008-04-01
      </capability>
    </hello>
  • 1
  • 2
  • 3
  • 4
  • 5

5.6.4.2 Features

服务器通过消息通告它所支持的features的名字。在消息中,features作为包含在URI中的“features”参数编码的。这个参数的值是以逗号为分隔符的feature名的列表。

比如,下面的消息声明了一个module,“syslog”,并告诉客户端它所支持的名为“local-storage”的feature。

<hello xmlns="urn:ietf:params:xml:ns:netconf:base:1.0">
  <capability>
    http://example.com/syslog?module=syslog&amp;features=local-storage
  </capability>
</hello>
  • 1
  • 2
  • 3
  • 4
  • 5

5.6.4.3 偏差(Deviations)

设备的偏差是通过“deviations”参数声明的。“deviations”参数的值是以逗号为分隔符的包含deviations的modules的列表。

比如,下面的消息通告了两个modules,告诉客户端它偏离module “syslog”的程度,这个程度具体是通过module “my-devs”声明出来的。

   <hello xmlns="urn:ietf:params:xml:ns:netconf:base:1.0">
       <capability>
         http://example.com/syslog?module=syslog&amp;deviations=my-devs
       </capability>
       <capability>
         http://example.com/my-deviations?module=my-devs
       </capability>
     </hello>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

但是这个偏差具体怎么描述也没有个说明,它的内容和“syslog”有怎样的关系?

5.7 Data Store Modification

Data models可能允许服务器选择不同的configuration data store的实现,而不仅仅是直接明确地通过NETCONF协议消息完成。比如,一个data model可能定义了一些系统生成的分配的值作为leafs,但是客户端可能并不支持。一种指定环境变量的通用机制(前提是这些环境变量允许修改)超出了本文档的讨论范围。

6 YANG Syntax

YANG语法类似于【RFC3780】定义的SMIng,以及编程语言C和C++。这种语法之所以和C相似,主要是为了可读性。since YANG values the time and effort of the readers of models above those of modules writers and YANG tool-chain developers. This section introduces the YANG syntax.

YANG modules使用【RFC3629】定义的UTF-8作为字符编码格式。

6.1 词汇的令牌化(Lexical Tokenization)

YANG modules在解析时会被分为多个tokens。本小节详细解释解析这些tokens的规则。YANG的令牌化规则是简单而强大的。简单之处在于其力图保持解析器的实现简单,强大之处在于模型设计者能够以一种易读的格式表现他们设计的models。

6.1.1 注释(Comments)

Comments是C++风格的。单行注释开始于“//”,结束于本行。块注释开始于“/*”,结束于“*/”。

6.1.2 Tokens

YANG中的一个token是一个keyword,string,semicolon(“;”),或者braces( “{” 或 “}” )。一个string可以是quoted或unquoted的。一个keyword可以是本文档中定义的YANG的关键词,或者是后面跟着冒号“:”,冒号后面跟着语言扩展关键词的前缀id。keywords是大小写敏感的。id的正式定义可见section 6.2。

什么是quoted和unquoted?意思是引号包括的和不用引号包括的。

6.1.3 引号包裹(Quoting)

如果一个string包含任何空格,制表符,分号(“;”),大括号( “{” 或 “}”),注释符号(“//”,“/*”,或“*/”),则它 MUST 用双引号或者单引号包括。

如果一个用双引号包括的string中包含一个换行符,换行符后面跟着的是空格或者制表符,该空格或制表符通常用来控制YANG文件中的文本布局。这些用于增强文本显示效果的留白在解析时会被从string中删掉,一直到第一个非空白字符为止。在该处理流程中,一个制表符被认为是8个空格符。

如果这个用双引号包括的string中在换行符前包含了空格或者制表符,这种行尾空格也会被从string中删掉。

一个单括号包裹的string(“””)则会保留单括号内的每一个字符。单括号字符不能出现在单括号包括的string中,即便使用反斜杠(“\”)做了转义也不可以。

在一个双括号包括的string理,使用转义字符(也就是反斜杠)会引入一个特殊字符,这取决于该转义字符后面跟着的是哪个字符:

\n      new line
\t      a tab character
\"      a double quote
\\      a single backslash
  • 1
  • 2
  • 3
  • 4
  • 5

如果一个括号包裹的string后面跟着一个加号(“+”),然后跟着另一个括号包裹的string,则这两个strings会被首尾衔接在一起,合并为一个string。在双括号包括的strings进行合并之前,该string要先完成空白字符的删除,以及转义字符的替换。

6.1.3.1 Quoting例子

下面的strings是等价的:

     hello
     "hello"
     'hello'
     "hel" + "lo"
     'hel' + "lo"
  • 1
  • 2
  • 3
  • 4
  • 5

下面的例子展示了一些特殊字符:

 "\""  - string containing a double quote
 '"'   - string containing a double quote
 "\n"  - string containing a new line character
 '\n'  - string containing a backslash followed
         by the character n
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

下面的例子展示了一些非法的字符串:

 ''''  - a single-quoted string cannot contain single quotes
 """   - a double quote must be escaped in a double-quoted string
  • 1
  • 2
  • 3

下面的字符串是等价的:

     "first line
        second line"

 "first line\n" + "  second line"          
  • 1
  • 2
  • 3
  • 4
  • 5

6.2 Identifiers

6.1.2中提到的id。

Identifiers被用来标识不同类型的YANG items。每个identifier都开始于一个大写,小写的ASCII字幕,或者是一个下划线,后面跟着0个或多个ASCII字幕,数字,下划线,连字符以及点。具体的实现 MUST 支持64个字符的长度。Identifiers是大小写敏感的。其语法规则的正式定义可见Section 12。Identifiers能被指定为quoted或unquoted strings。

其实看了也不明白这个identifier的具体用途在哪里

6.2.1 Identifiers和它们的Namespaces

每个identifier在一个namespace中都是有效的,而namespace取决于YANG item被定义的类型。所有的定义在一个namespace中的identifiers都必须是唯一的。

  • 所有的module和submodule的名字都共享同一个全局的module identifier namespace。
  • 在module以及它的submodules中定义的所有扩展名都共享同一个extension identifier namespace。
  • 所有定义在module以及它的submodules的identity names都共享同一个identity identifier namespace。
  • 所有定义在module以及它的submodules的父节点或者顶级节点的派生类型的名字(derived type names)都共享同一个type identifier namespace。这个namespace对于该父节点或者module的所有下行节点都有效。这意味着任何下行节点都有可能使用typedef,并且 MUST NOT 定义和其它type名相同的名字。
  • 所有定义在module以及它的submodules的父节点或者顶级节点的grouping names都共享同一个grouping identifier namespace。这个namespace对于该父节点或者module的所有下行节点都有效。这意味着任何下行节点都有可能使用grouping,并且 MUST NOT 定义和其它grouping名相同的名字。
  • 所有定义在module以及它的submodules的父节点或者顶级节点的leafs,leaf-lists,lists,containers,choices,rpcs,notifications以及anyxmls(直接或者通过“use”声明定义的 )都共享同一个identifier namespace。这个namespace对于该父节点或者module都有效,除非父节点是一个case node。在那种情况下,这个namespace对于非case或choice节点的最近的祖先节点。
  • 所有在包含在“choice”中的“case”都共享同一个case identifier namespace。这个namespace在父choice node中有效。

这里还是有问题啊,第六项中,这个namespace对于该父节点或者module有效,而不是对该父节点或者module的所有下行节点都有效。这里是不是有错误啊? 
另外,顶级节点的作用范围是不是就对应着整个module啊。

YANG语言中允许前向引用(Forward references)。

6.3 声明(Statements)

一个YANG module包含了一系列的statements。每个statement开始于一个keyword,后面跟着0个或一个参数,然后或者跟着一个分号表示结束,或者跟着用大括号包裹的substatements块:

 statement = keyword [argument] (";" / "{" *statement "}")
  • 1
  • 2

如果Section 6.1.2的定义,这个参数是一个string。

6.3.1 语言扩展(Language Extensions)

在一个module中,可以使用“extension”关键词(见Section 7.17)引入YANG extensions。扩展也可以被其它modules使用“import”声明导入(见Section 7.1.5)。当一个被导入的扩展被使用时,该扩展的关键词 MUST 使用该扩展被定义的module的名字作为前缀以示区别。如果扩展在它被定义的module中使用,则其关键词也 MUST 使用module的前缀。由于submodules不能包括其parent module,因此,所有需要在submodules中用到的扩展都 MUST 定义在submodule中。然后其它的submodules能够通过包含该submodule使用该扩展。

复习一下,submodule叫include,module叫import。

如果一个YANG编译器不支持特定的扩展,具体表现为在一个YANG module中出现未知的statement(见Section 12),则整个未知的statement包含的内容 MAY 被编译器忽略。

6.4 XPath Evaluations

XPath的简介可见http://www.w3school.com.cn/xpath/xpath_intro.asp

XPath 是一门在 XML 文档中查找信息的语言。XPath 用于在 XML 文档中通过元素和属性进行导航。XPath 使用路径表达式来选取 XML 文档中的节点或者节点集。这些路径表达式和我们在常规的电脑文件系统中看到的表达式非常相似。在 XPath 中,有七种类型的节点:元素、属性、文本、命名空间、处理指令、注释以及文档节点(或称为根节点)。

YANG依赖XML Path Language(XPath) 1.0,将其作为标记表达节点之间的引用和依赖关系。NETCONF的客户端和服务端并不强制要求实现XPath解释器,但是 MUST 确保data model中编码的requirements是强制执行的。执行的方式由实际实现决定。XPath表达式 MUST 在语法结构上保证正确无误,所有使用的前缀 MUST在当前的XPath context中是现成可用的(见Section 6.4.1)。有种实现会选择手动实现这些,而不是直接使用XPath表达式。

什么叫确保data model中编码的requirements是强制的。原文是

NETCONF clients and servers are not required to implement an XPath interpreter, but MUST ensure that the requirements encoded in the data model are enforced. The manner of enforcement is an implementation decision.

The data model used in the XPath expressions is the same as that used 
in XPath 1.0 [XPATH], with the same extension for root node children 
as used by XSLT 1.0 [XSLT] (Section 3.1). Specifically, it means 
that the root node may have any number of element nodes as its 
children.

6.4.1 XPath Context

所有的YANG XPath表达式都共享下面的XPath context定义:

  • The set of namespace declarations is the set of all “import” statements’ prefix and namespace pairs in the module where the XPath expression is specified, and the “prefix” statement’s prefix for the “namespace” statement’s URI.
  • Names without a namespace prefix belong to the same namespace as the identifier of the current node. Inside a grouping, that namespace is affected by where the grouping is used (see Section 7.12).
  • The function library is the core function library defined in [XPATH], and a function “current()” that returns a node set with the initial context node.
  • The set of variable bindings is empty.

The mechanism for handling unprefixed names is adopted from XPath 2.0 [XPATH2.0], and helps simplify XPath expressions in YANG. No ambiguity may ever arise because YANG node identifiers are always qualified names with a non-null namespace URI.

The context node varies with the YANG XPath expression, and is specified where the YANG statement with the XPath expression is defined.

6.5 Schema Node Identifier

这一块可是重中之重啊,在ODL的YANGTools中,首先要做的就是解析参数为SchemaNodeIdentifier。

一个schema node identifier是一个string,表明了schema tree中的一个节点。它有两种表达形式,“absolute”(绝对路径)和“descendant”(相对路径),其规则分别由Section 12中的“absolute-schema-nodeid”和“descendant-schema-nodeid”制定。一个shema node identifier是由用斜杠(“/”)分隔的不同id组合而成的path组成的。在一个absolute schema node identifier中,第一个斜杠后面的第一个identifier是本module或所有其它被导入的modules的顶级schema node。

定义在外部modules的对identifiers的引用 MUST 使用合适的前缀描述,在当前module以及它的submodules中引用的identifiers MSY 使用前缀。

比如,为了表示在顶级节点“a”下的子节点“b”,可以使用字符串“/a/b”。

7 YANG Statements

接下来的小节描述了所有的YANG statements。

需要明确一点,即便是在YANG中没有定义任何substatements的statement也能有设备商制定的扩展作为substatements。比如,“description”声明在YANG定义中没有任何substatements,但是下面的写法是合法的:

 description "some text" {
     acme:documentation-flag 5;
 }
  • 1
  • 2
  • 3
  • 4

7.1 Module Statement

“module”声明定义了module的名字,将所有属于该module的声明都集中在一起。“module”声明的参数就是该module的名字,后面跟着一块substatements,其中包含了该module具体的信息。module的名字服从Section 6.2中针对identifiers的规则。

在RFC streams 【RFC 
4844
】中发布的modules的名字 MUST 由IANA分配,可见Section 14。

私有的module的名字是由拥有该module的组织分配的。 RECOMMENDED 私有module的名字和标准中的modules以及其它组织的module没有命名冲突。

一个module的典型布局如下:

 module <module-name> {

     // header information
     <yang-version statement>
     <namespace statement>
     <prefix statement>

     // linkage statements
     <import statements>
     <include statements>

     // meta information
     <organization statement>
     <contact statement>
     <description statement>
     <reference statement>

     // revision history
     <revision statements>

     // module definitions
     <other statements>
 }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24

7.1.1 module的substatements

             +--------------+---------+-------------+
             | substatement | section | cardinality |
             +--------------+---------+-------------+
             | anyxml       | 7.10    | 0..n        |
             | augment      | 7.15    | 0..n        |
             | choice       | 7.9     | 0..n        |
             | contact      | 7.1.8   | 0..1        |
             | container    | 7.5     | 0..n        |
             | description  | 7.19.3  | 0..1        |
             | deviation    | 7.18.3  | 0..n        |
             | extension    | 7.17    | 0..n        |
             | feature      | 7.18.1  | 0..n        |
             | grouping     | 7.11    | 0..n        |
             | identity     | 7.16    | 0..n        |
             | import       | 7.1.5   | 0..n        |
             | include      | 7.1.6   | 0..n        |
             | leaf         | 7.6     | 0..n        |
             | leaf-list    | 7.7     | 0..n        |
             | list         | 7.8     | 0..n        |
             | namespace    | 7.1.3   | 1           |
             | notification | 7.14    | 0..n        |
             | organization | 7.1.7   | 0..1        |
             | prefix       | 7.1.4   | 1           |
             | reference    | 7.19.4  | 0..1        |
             | revision     | 7.1.9   | 0..n        |
             | rpc          | 7.13    | 0..n        |
             | typedef      | 7.3     | 0..n        |
             | uses         | 7.12    | 0..n        |
             | yang-version | 7.1.2   | 0..1        |
             +--------------+---------+-------------+
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31

上面的0..1,表示可以出现0次到1次,0..n表示可以出现任意次数,1表示能且仅能出现一次。

7.1.2 yang-version声明

“yang-version”是可选的,指定了本module使用的YANG语言的版本号。这个声明的参数是一个字符串。如果出现,它必须包含值“1”,这是YANG语言目前的版本号,也是默认的版本号。

version 1.1已经有了。不过还不知道是哪个RFC。

对于值非“1”的“yang-version”的处理超出了本文档的讨论范围。任何定义更高版本的文档都需要保持版本向前兼容。

7.1.3 namespace声明

“namespace”声明定义了module中所有的identifiers所属的XML namespace,除了定义在一个grouping中的data node identifiers以外(见Section 7.12)。它的参数是这个namespace的URI。

详情可减Section 5.3。

7.1.4 prefix声明

“prefix”声明呗用来定义和module以及它的namespace相关联的前缀。“prefix”声明的参数是一个前缀字符串。这个字符串 MAY 指向包含在本module中的定义,比如“if:ifName”。prefix遵循和identifier相同的规则(见Section 6.2)。

当在“module”声明中使用它时,“prefix”声明定义了当该module被其它module导入时需要使用的前缀。为了提高NETCONF XML的可读性,一个使用该前缀生成XML或者XPath的NETCONF的客户端或者服务端 SHOULD 使用这个前缀,除非出现了冲突。(To improve readability of the NETCONF XML, a NETCONF client or server that generates XML or XPath that use prefixes SHOULD use the prefix defined by the module, unless there is a conflict.

当在“import”声明中使用它时,“prefix”声明定义了访问被导入module中的定义时需要使用的前缀。当需要引用一个被导入module的identifier时,被导入module的前缀字符串会被放在identifier前面,用冒号隔开,比如“if:ifIndex”。为了提高YANG modules的可读性,module中定义的prefix SHOULD 在该module被导入时使用,除非出现了prefix conflict。如果出现了冲突,比如两个拥有同样prefix名的不同的modules同时被导入,则至少有一个 MUST 改变其prefix。

所有的prefixes,包括module自己本身的prefix,都 MUST 在该module或者submodule内部保持唯一。

这里用了module或者submodule内部保持唯一。

7.1.5 import声明

“import”声明使得一个module的定义能够在另一个module或submodule内部被使用。它的参数是被导入的module的名字,其后跟着一块包含具体导入信息的substatements。当一个module被导入时,导入它的module可能:

  • 使用被导入module或者它的submodules中的任何grouping和typedef。
  • 使用被导入module或者它的submodules中的任何extension,feature,以及identity。
  • 使用被导入module的schema tree中的“must”,“path”,以及“when”声明中的任何node,或者作为“augment”和“deviation”声明的target node。

The mandatory “prefix” substatement assigns a prefix for the imported module that is scoped to the importing module or submodule. Multiple “import” statements may be specified to import from different modules.

当可选的“revision-date” substatement在“import”声明中出现时,任何本地module的定义中引用的typedef,grouping,extension,feature以及identity都是从指定revision的module中导入的。如果指定的revision不存在,则会出现错误。如果没有“revision-date”出现,则导入的module的revision不确定。

对于同一个module的多个revisions的导入是 MUST NOT 的。

                    The import's Substatements

             +---------------+---------+-------------+
             | substatement  | section | cardinality |
             +---------------+---------+-------------+
             | prefix        | 7.1.4   | 1           |
             | revision-date | 7.1.5.1 | 0..1        |
             +---------------+---------+-------------+
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

7.1.5.1 import的revision-date声明

“revision-date”声明用来指定module的具体版本号。其值 MUST 和被导入module的“revision”声明的值匹配。

7.1.6 include声明

“include”声明被用来将某个submodule的内容对于其父module,或者父module之下的其他submodule可用。其参数是一个identifier,表示被包含的submodule的名字。modules只能包含属于它的用“belongs-to”声明定义的submodules,submodules只能包含和它属于同一个module的其他submodule。

当一个module包含了一个submodule,它就会将这个submodule的内容组合进本module的node hierarchy中。当一个submodule包含了另一个submodule,则另一个submodule的定义对于当前的submodule就是可用的。

当可选的“revision-date” substatement出现,指定revision的submodule会被包含到module中。如果指定revision的submodule不存在,则会出现错误。如果没有“revision-date” substatement出现,则没有定义哪个revision的submodule会被包含。

对于同一个submodule的多个revisions的导入是 MUST NOT 的。

                   The includes's Substatements

             +---------------+---------+-------------+
             | substatement  | section | cardinality |
             +---------------+---------+-------------+
             | revision-date | 7.1.5.1 | 0..1        |
             +---------------+---------+-------------+
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

7.1.7 organization声明

“organization”声明定义了对该module负责的团体名。其参数是特定组织的文本描述的字符串。

7.1.8 contact声明

“contact”声明提供了该module的相关联系信息。该参数是一个字符串,包含了指定联系人的名字,邮件地址,电话号码,电子邮箱等信息,技术相关的疑问都可以咨询他。

7.1.9 revision声明

“revision”声明指定了该module的编辑版本历史,包括最初的一版。一系列的revision声明能够详细描述该module定义上发生的改变细节。其参数是一个日期字符串,格式为“YYYY-MM-DD”,后面跟着一块包含详细revision信息的substatements。一个module SHOULD 至少有一个初始的“revision”声明。对于每次发布的修改,都 SHOULD 增加一个revision。

7.1.9.1 revision的substatement

             +--------------+---------+-------------+
             | substatement | section | cardinality |
             +--------------+---------+-------------+
             | description  | 7.19.3  | 0..1        |
             | reference    | 7.19.4  | 0..1        |
             +--------------+---------+-------------+
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

7.1.10 使用用例

 module acme-system {
     namespace "http://acme.example.com/system";
     prefix "acme";

     import ietf-yang-types {
         prefix "yang";
     }

     include acme-types;

     organization "ACME Inc.";
     contact
         "Joe L. User

          ACME, Inc.
          42 Anywhere Drive
          Nowhere, CA 95134
          USA

          Phone: +1 800 555 0100
          EMail: joe@acme.example.com";

     description
         "The module for entities implementing the ACME protocol.";

     revision "2007-06-09" {
         description "Initial revision.";
     }

     // definitions follow...
 }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32

7.2 submodule声明

YANG中最基本的单位是module,一个YANG module本身能够由多个submodules构成。submodules的存在使得module设计者能够将一个复杂的model分割成多个共用同一个namespace的submodules,而namespace是由module定义的。

“submodule”声明定义了submodule的名字,将属于该submodule的所有声明都整合到了一起。其参数是submodule的名字,后面跟着相关的详细substatements信息。submodule名字遵从identifiers的规则,可见Section 6.2。

在RFC streams 【RFC4844】中发布的submodules的名字都 MUST 由IANA分配,可见Section 14。

Private submodule names are assigned by the organization owning the 
submodule without a central registry. It is RECOMMENDED to choose 
submodule names that will have a low probability of colliding with 
standard or other enterprise modules and submodules, e.g., by using 
the enterprise or organization name as a prefix for the submodule 
name.

一个经典的submodule的文本布局如下:

 submodule <module-name> {

     <yang-version statement>

     // module identification
     <belongs-to statement>

     // linkage statements
     <import statements>
     <include statements>

     // meta information
     <organization statement>
     <contact statement>
     <description statement>
     <reference statement>

     // revision history
     <revision statements>

     // module definitions
     <other statements>
 }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24

7.2.1 submodule的substatements

             +--------------+---------+-------------+
             | substatement | section | cardinality |
             +--------------+---------+-------------+
             | anyxml       | 7.10    | 0..n        |
             | augment      | 7.15    | 0..n        |
           * | belongs-to   | 7.2.2   | 1           | 
             | choice       | 7.9     | 0..n        |
             | contact      | 7.1.8   | 0..1        |
             | container    | 7.5     | 0..n        |
             | description  | 7.19.3  | 0..1        |
             | deviation    | 7.18.3  | 0..n        |
             | extension    | 7.17    | 0..n        |
             | feature      | 7.18.1  | 0..n        |
             | grouping     | 7.11    | 0..n        |
             | identity     | 7.16    | 0..n        |
             | import       | 7.1.5   | 0..n        |
             | include      | 7.1.6   | 0..n        |
             | leaf         | 7.6     | 0..n        |
             | leaf-list    | 7.7     | 0..n        |
             | list         | 7.8     | 0..n        |
             | notification | 7.14    | 0..n        |
             | organization | 7.1.7   | 0..1        |
             | reference    | 7.19.4  | 0..1        |
             | revision     | 7.1.9   | 0..n        |
             | rpc          | 7.13    | 0..n        |
             | typedef      | 7.3     | 0..n        |
             | uses         | 7.12    | 0..n        |
             | yang-version | 7.1.2   | 0..1        |
             +--------------+---------+-------------+
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30

和module相比,多了一个belongs-to,少了一个prefix。

7.2.2 belongs-to声明

“belongs-to”声明指定了submodule所属的module。其参数是module名字。

一个submodule MUST 只能被它所属的module,或者被它所属的module的其它submodules包含。

“belongs-to”声明有一个必须出现的“prefix”声明,该声明指定了所属的module的prefix。在本地submodule中的所有定义,以及它所包含的submodules都能通过这个prefix访问。

                  The belongs-to's Substatements

             +--------------+---------+-------------+
             | substatement | section | cardinality |
             +--------------+---------+-------------+
             | prefix       | 7.1.4   | 1           |
             +--------------+---------+-------------+
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

7.2.3 使用用例

 submodule acme-types {

     belongs-to "acme-system" {
         prefix "acme";
     }

     import ietf-yang-types {
         prefix "yang";
     }

     organization "ACME Inc.";
     contact
         "Joe L. User

          ACME, Inc.
          42 Anywhere Drive
          Nowhere, CA 95134
          USA

          Phone: +1 800 555 0100
          EMail: joe@acme.example.com";

     description
         "This submodule defines common ACME types.";

     revision "2007-06-09" {
         description "Initial revision.";
     }

     // definitions follows...
 }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32

7.3 typedef声明

根据Section 5.5中的规则,“typedef”声明定义了一个新的type,能够在module内部,包含该module的modules或submodules,以及导入该module的其它modules使用。新的type称为“derived type”(派生类型),被派生的类型称为“base type”(基本类型)。所有的派生类型都能最重追溯到YANG的内置类型。

“typedef”声明的参数是一个identifier,该id就是新定义的类型的名字,其后面 MUST 跟着包含typedef详细信息的一块substatements。

这个type的名字 MUST NOT 是YANG的内置类型。如果typedef定义在YANG module或submodule的top level,则其名字 MUST 在整个module中保持唯一。

7.3.1 typedef的substatements

             +--------------+---------+-------------+
             | substatement | section | cardinality |
             +--------------+---------+-------------+
             | default      | 7.3.4   | 0..1        |
             | description  | 7.19.3  | 0..1        |
             | reference    | 7.19.4  | 0..1        |
             | status       | 7.19.2  | 0..1        |
             | type         | 7.3.2   | 1           |
             | units        | 7.3.3   | 0..1        |
             +--------------+---------+-------------+
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

7.3.2 typedef的type声明

“type”声明 MSUT 出现在typedef中,定义了新定义type所派生的基本类型。可见Section 7.4。

7.3.3 units声明

“units”声明是可选的,其内容是一个字符串,包含了和这个type相关的units的文本定义。

7.3.4 typedef的default声明

“default”声明的参数是新的type的默认值。

“default”声明的值 MUST 是有效的。

如果base type有一个默认值,新的派生类型没有指定新的默认值,则base type的默认值也是新的派生类型的默认值。

如果这个type的默认值,在派生类型或者leaf的定义中,根据相关restrictions,是无效的,则派生类型或leaf定义就 MUST指定一个新的默认值,以匹配restrictions。

7.3.5 使用用例

 typedef listen-ipv4-address {
     type inet:ipv4-address;
     default "0.0.0.0";
 }
  • 1
  • 2
  • 3
  • 4
  • 5

7.4 type声明

“type”声明的参数是YANG的内置类型(见Section 9)或者派生类型(见Section 7.3),后面跟着可选的一块substatements,用于进一步对该type施加限制(restrictions)。

所有内置类型能够使用的restriction声明取决于被限定的类型。

7.4.1 type的substatements

           +------------------+---------+-------------+
           | substatement     | section | cardinality |
           +------------------+---------+-------------+
           | bit              | 9.7.4   | 0..n        |
           | enum             | 9.6.4   | 0..n        |
           | length           | 9.4.4   | 0..1        |
           | path             | 9.9.2   | 0..1        |
           | pattern          | 9.4.6   | 0..n        |
           | range            | 9.2.4   | 0..1        |
           | require-instance | 9.13.2  | 0..1        |
           | type             | 7.4     | 0..n        |
           +------------------+---------+-------------+
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

没清楚这里使用type有什么意义?需要例子。

7.5 constainer声明

“container”声明被用来定义一个schema tree中包含的内部数据节点(interior data node)。它有一个参数,是一个identifier,后面跟着一块描述进详细信息的substatements。

一个container节点没有一个值,但是在data tree中有一个列表的子节点。子节点都定义在container的substatements中。

7.5.1 Containers with Presence

YANG支持两种风格的containers,一种仅仅用于组织data nodes的垂直结构,一种出现在configuration中,有明确的意义。

第一种风格中,container本身没有任何意义,它的存在仅仅是为了包含子节点。这是默认的风格。

比如,同步光网络(SONET)的scrambling options的集合能被放到一个名为“scrambling”的container中,以增强配置结构的层次化,将这些节点整合到一起。这个“scrambling”节点本身没有意义,所以在它变成空的的时候可以移除该节点。

在第二种风格中,container本身就是配置型数据(configuration)data,表示配置型数据的一个简单bit。The container acts as both a configuration knob and a means of organizing related configuration. 这些containers的创建和删除操作都必须是明确无误的。

YANG称这种风格的container为一个“presence container”,这表示要使用“presence”声明,作为它的

比如,一个“ssh”的container可能会启动使用ssh方式将日志写进设备的能力,不过也能包含任何和ssh相关的configuration knobs,比如连接速率和重试次数限制。

“presence”声明(见Section 7.5.5)用来在data tree中给container的存在以语义。

说这么多,都不如一个demo来的实在。真的是没看懂啊。

7.5.2 container的substatements

             +--------------+---------+-------------+
             | substatement | section | cardinality |
             +--------------+---------+-------------+
             | anyxml       | 7.10    | 0..n        |
             | choice       | 7.9     | 0..n        |
             | config       | 7.19.1  | 0..1        |
             | container    | 7.5     | 0..n        |
             | description  | 7.19.3  | 0..1        |
             | grouping     | 7.11    | 0..n        |
             | if-feature   | 7.18.2  | 0..n        |
             | leaf         | 7.6     | 0..n        |
             | leaf-list    | 7.7     | 0..n        |
             | list         | 7.8     | 0..n        |
             | must         | 7.5.3   | 0..n        |
             | presence     | 7.5.5   | 0..1        |
             | reference    | 7.19.4  | 0..1        |
             | status       | 7.19.2  | 0..1        |
             | typedef      | 7.3     | 0..n        |
             | uses         | 7.12    | 0..n        |
             | when         | 7.19.5  | 0..1        |
             +--------------+---------+-------------+
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22

7.5.3 must声明

“must”声明是可选的,其参数是一个字符串包含了一个XPath表达式(见Section 6.4)。它被用来正式声明有效数据上的约束。约束根据Section 8的规则执行。

当一个datastore可用时,所有的“must”约束都会对data tree中的每个data node,对于使用默认值的所有leafs(见Section 7.6.1)进行概念上的评估。如果一个data node在data tree中并不存在,并且没有一个默认值,则它的“must”声明不会被评估。(When a datastore is validated, all “must” constraints are conceptually evaluated once for each data node in the data tree, and for all leafs with default values in use (see Section 7.6.1). 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.

所有这样的约束 MUST 评估为true,这样data才是有效的。

XPath表达式在下述的上下文,以及Section 6.4.1的定义中也要进行概念上的评估(conceptually evaluated):

  • The context node is the node in the data tree for which the “must” statement is defined.
  • The accessible tree is made up of all nodes in the data tree, and all leafs with default values in use (see Section 7.6.1).

可访问的tree取决于context node:

  • If the context node represents configuration, the tree is the data in the NETCONF datastore where the context node exists. The XPath root node has all top-level configuration data nodes in all modules as children.
  • If the context node represents state data, the tree is all state data on the device, and the datastore. The XPath root node has all top-level data nodes in all modules as children.
  • If the context node represents notification content, the tree is the notification XML instance document. The XPath root node has the element representing the notification being defined as the only child.
  • If the context node represents RPC input parameters, the tree is the RPC XML instance document. The XPath root node has the element representing the RPC operation being defined as the only child.
  • If the context node represents RPC output parameters, the tree is the RPC reply instance document. The XPath root node has the elements representing the RPC output parameters as children.

使用标准的XPath规则评估的XPath表达式的结果会被转化为一个boolean值。

Note that since all leaf values in the data tree are conceptually stored in their canonical form (see Sections 7.6 and 7.7), any XPath comparisons are done on the canonical value.

Also note that the XPath expression is conceptually evaluated. This means that an implementation does not have to use an XPath evaluator on the device. How the evaluation is done in practice is an implementation decision.

7.5.4 must的substatements

             +---------------+---------+-------------+
             | substatement  | section | cardinality |
             +---------------+---------+-------------+
             | description   | 7.19.3  | 0..1        |
             | error-app-tag | 7.5.4.2 | 0..1        |
             | error-message | 7.5.4.1 | 0..1        |
             | reference     | 7.19.4  | 0..1        |
             +---------------+---------+-------------+
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

7.5.4.1 error-message声明

“error-message”声明是可选的,其参数是一个字符串。如果约束的评估结果为false,这个字符串会被放在的中。

7.5.4.2 error-app-tag声明

“error-app-tag”声明是可选的,其参数是一个字符串。如果约束的评估结果为false,这个字符串会被放在的中。

7.5.4.3 must和error-message的使用用例

 container interface {
     leaf ifType {
         type enumeration {
             enum ethernet;
             enum atm;
         }
     }
     leaf ifMTU {
         type uint32;
     }
     must "ifType != 'ethernet' or " +
          "(ifType = 'ethernet' and ifMTU = 1500)" {
         error-message "An ethernet MTU must be 1500";
     }
     must "ifType != 'atm' or " +
          "(ifType = 'atm' and ifMTU <= 17966 and ifMTU >= 64)" {
         error-message "An atm MTU must be  64 .. 17966";
     }
 }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20

7.5.5 presence声明

“presence”声明指定了在data tree中一个container的presence的含义。它的参数是一个字符串,包含了node的presence means的文本描述。

如果一个container有“presence”声明,则存在于data tree中的该container就是有意义的。否则,该container就是第一类型的container,仅仅用于将数据结构化,本身并不携带任何意义。

更多信息可见Section 7.5.1。

简单来说,这个声明存在的意义就是用来判别container是第一类还是第二类的。不过没有见到哪个文档里有具体的实现啊。

7.5.6 container的child node声明

在一个container中,child nodes可以是“container”,“leaf”,“list”,“leaf-list”,“uses”,“choice”,以及“anyxml”声明。

7.5.7 XML 映射规则

一个container节点被编码为一个XML element。这个element的local name就是container的identifier,它的namespace就是module的XML namespace(见Section 7.1.3)。

container的child nodes被编码为container element的subelements。如果container定义了RPC input或output参数,这些subelements被编码的顺序和它们在“container”声明中定义的顺序一致。否则,subelements的编码顺序随意。

一个NETCONF服务端在回复一个或请求的时候,如果container node没有“presence”声明并且没有child nodes存在,则 MAY 不会发送这个container element作为回复。因此,一个发送或后获得回复的客户端,必须能够处理一种情况,那就是在XML中没有不包含“presence”声明的container node。

涉及到NETCONF的时候就一脸蒙逼。

7.5.8 NETCONF 操作

containers可以通过在中使用“operation”属性(见【RFC4741】 Section 7.2)被创建,删除,替换和修改。

如果一个container没有包含“presence”声明,并且最后一个child node都被删除了,则NETCONF服务端 MAY 删除这个container。当一个NETCONF服务端处理一个请求的时候,container node的处理流程如下:

  • 如果operation是“merge”或者“replace”,当该node不存在时则会被创建。
  • 如果operation是“create”,当该node不存在时会被创建。如果该node已经存在了,则会返回一个“data-exists”错误。
  • 如果operation是“delete”,当该node存在时会被哦删除。如果该node不存在,则会返回“data-missing”错误。

7.5.9 使用用例

给出下面的container的定义:

 container system {
     description "Contains various system parameters";
     container services {
         description "Configure externally available services";
         container "ssh" {
             presence "Enables SSH";
             description "SSH service specific configuration";
             // more leafs, containers and stuff here...
         }
     }
 }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

对应的XML实例为:

 <system>
   <services>
     <ssh/>
   </services>
 </system>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

由于 element出现了,所以ssh是enabled的。

使用删除一个container:

 <rpc message-id="101"
      xmlns="urn:ietf:params:xml:ns:netconf:base:1.0"
      xmlns:nc="urn:ietf:params:xml:ns:netconf:base:1.0">
   <edit-config>
     <target>
       <running/>
     </target>
     <config>
       <system xmlns="http://example.com/schema/config">
         <services>
           <ssh nc:operation="delete"/>
         </services>
       </system>
     </config>
   </edit-config>
 </rpc>     
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17

7.6 leaf声明

“leaf”声明被用来在schema tree中定义一个leaf node。它只有一个参数,是identifier,后面跟着详细描述该leaf信息的一块substatements。

一个leaf node有一个值,但是在data tree中没有child nodes。概念上将,data tree中的值总是以canonical form存在的(见Section 9.1)。

在data tree中存在0个或者1个leaf node。

“leaf”声明被用来定义一个特定类型的标量变量。

7.6.1 leaf的默认值(default value)

一个leaf的默认值是当在data tree中没有该leaf存在时,服务端采用的值。默认值的采用取决于schema tree中离该leaf最近的带有“presence” 的container的祖先节点:

  • 如果在schema tree中没有这样的祖先节点,则默认值 MUST 被使用
  • 否则,如果这个祖先节点是一个case node,则如果data tree中有任何该case的node存在,或者这个case node就是choice的默认case,并且data tree中没有任何其它的case存在,这样一来就必须使用默认值。
  • 再否则,如果在data tree中有这样的祖先节点存在,则默认值 MUST 被使用。

表示完全看不懂上面说了些啥?并且不明白为什么这么设置。

在这些例子中,默认值都要被使用。

当默认值被使用的时候,服务端 MUST 表现得好像这个值为默认值的这个leaf node就存在于data tree中一样。

如果一个leaf有一个“default”声明,则该leaf的默认值就是“default”声明指定的值。否则,如果leaf的type有一个默认的值,并且该leaf不是强制出现(mandatory)的,则该leaf的默认值就是该type的默认值。在所有其它情况下,这个leaf没有一个默认值。

7.6.2 leaf的substatements

             +--------------+---------+-------------+
             | substatement | section | cardinality |
             +--------------+---------+-------------+
             | config       | 7.19.1  | 0..1        |
             | default      | 7.6.4   | 0..1        |
             | description  | 7.19.3  | 0..1        |
             | if-feature   | 7.18.2  | 0..n        |
             | mandatory    | 7.6.5   | 0..1        |
             | must         | 7.5.3   | 0..n        |
             | reference    | 7.19.4  | 0..1        |
             | status       | 7.19.2  | 0..1        |
             | type         | 7.6.3   | 1           |
             | units        | 7.3.3   | 0..1        |
             | when         | 7.19.5  | 0..1        |
             +--------------+---------+-------------+
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

7.6.3 leaf的type声明

“type”声明, MUST要出现,有一个参数,是当前已有的内置或者佩声类型。在这个type上有可选的substatements指定了相关的restrictions。可见Section 7.4。

7.6.4 leaf的default声明

“default”声明,是可选的,其参数是一个字符串,包含了leaf的默认值。

“default”声明的值 MUST是有效可用的,不能违背对应type的规则。

如果“mantory”为true,则“default”声明 MUST NOT 不能出现在nodes中。

7.6.5 leaf的mandatory声明

The “mandatory” statement, which is optional, takes as an argument 
the string “true” or “false”, and puts a constraint on valid data. 
If not specified, the default is “false”.

If “mandatory” is “true”, the behavior of the constraint depends on 
the type of the leaf’s closest ancestor node in the schema tree that 
is not a non-presence container (see Section 7.5.1):

o If no such ancestor exists in the schema tree, the leaf MUST 
exist.

o Otherwise, if this ancestor is a case node, the leaf MUST exist if 
any node from the case exists in the data tree.

o Otherwise, the leaf MUST exist if the ancestor node exists in the 
data tree.

This constraint is enforced according to the rules in Section 8.

7.6.6 XML映射规则

  A leaf node is encoded as an XML element.  The element's local name
  • 1
  • 2

is the leaf’s identifier, and its namespace is the module’s XML 
namespace (see Section 7.1.3).

The value of the leaf node is encoded to XML according to the type, 
and sent as character data in the element.

A NETCONF server that replies to a or request MAY 
choose not to send the leaf element if its value is the default 
value. Thus, a client that receives an for a or 
request, MUST be prepared to handle the case that a leaf 
node with a default value is not present in the XML. In this case, 
the value used by the server is known to be the default value.

See Section 7.6.8 for an example.

7.6.7 NETCONF Operations

When a NETCONF server processes an request, the 
elements of procedure for the leaf node are:

  If the operation is "merge" or "replace", the node is created if
  it does not exist, and its value is set to the value found in the
  XML RPC data.

  If the operation is "create", the node is created if it does not
  exist.  If the node already exists, a "data-exists" error is
  returned.

  If the operation is "delete", the node is deleted if it exists.
  If the node does not exist, a "data-missing" error is returned.
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

7.6.8 使用实例

给定下面的“leaf”声明,放到之前定义的 “ssh”的container中(可见Section 7.5.9):

 leaf port {
     type inet:port-number;
     default 22;
     description "The port to which the SSH server listens"
 }      
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

对应的XML实例为:

 <port>2022</port>
  • 1
  • 2

在中设置该leaf的值:

 <rpc message-id="101"
      xmlns="urn:ietf:params:xml:ns:netconf:base:1.0"
      xmlns:nc="urn:ietf:params:xml:ns:netconf:base:1.0">
   <edit-config>
     <target>
       <running/>
     </target>
     <config>
       <system xmlns="http://example.com/schema/config">
         <services>
           <ssh>
             <port>2022</port>
           </ssh>
         </services>
       </system>
     </config>
   </edit-config>
 </rpc>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19

7.7 leaf-list声明

“leaf”声明是被用来定义一个简单的特定类型的标量变量,而“leaf-list”声明被用来定义特定类型的一个数组。“leaf-list”声明有一个参数,是一个identifier,后面跟着描述具体内容的一块substatements。

“leaf-list”的值 MUST 是唯一的。

概念上来讲,data tree中的值总是以canonical form存在的(见Section 9.1)。

如果“leaf-list”引用的type有默认值,默认值对leaf-list产生什么影响(If the type referenced by the leaf-list has a default value, it has no effect in the leaf-list.)。

7.7.1 排序

对于“list”和“leaf-list”声明,YANG支持两种风格的排序方式。在很多lists中,为了使被排列的列表项不影响列表配置的具体实现,设备能够以任何合理的顺序给list的列表项进行排序。不过在“description”中可能会有关于排序的建议。YANG称这种风格为“system ordered”,这种排序的声明为“ordered-by system”。

比如,有时候为了对到来的流量进行过滤,防火墙的过滤条件列表项的顺序就变得有用。用户可能需要决定丢弃所有TCP流量的过滤项是放在允许信任接口流量通过的过滤项之前还是之后。这时候对于列表的排序就至关重要了。

YANG为NETCONF的操作提供了丰富的特性集以便列表能够以用户规定的方式进行排序。列表项可能会被插入,或重新排列到列表的第一项或最后一项,或者放到某一个特定列表项的前面或者后面。

“ordered-by”声明在Section 7.7.5 中有所包含。

7.7.2 leaf-list的substatements

             +--------------+---------+-------------+
             | substatement | section | cardinality |
             +--------------+---------+-------------+
             | config       | 7.19.1  | 0..1        |
             | description  | 7.19.3  | 0..1        |
             | if-feature   | 7.18.2  | 0..n        |
             | max-elements | 7.7.4   | 0..1        |
             | min-elements | 7.7.3   | 0..1        |
             | must         | 7.5.3   | 0..n        |
             | ordered-by   | 7.7.5   | 0..1        |
             | reference    | 7.19.4  | 0..1        |
             | status       | 7.19.2  | 0..1        |
             | type         | 7.4     | 1           |
             | units        | 7.3.3   | 0..1        |
             | when         | 7.19.5  | 0..1        |
             +--------------+---------+-------------+
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17

7.7.3 min-elements声明

“min-elements”声明,是可选的,取值为一个非负的整型,是对有效列表项的一个约束。一个可用的“leaf-list”或者“list” MUST 至少有min-elements个列表项。

如果该声明不存在,则默认为0。

The behavior of the constraint depends on the type of the leaf-list’s 
or list’s closest ancestor node in the schema tree that is not a non- 
presence container (see Section 7.5.1):

o If this ancestor is a case node, the constraint is enforced if any 
other node from the case exists.

o Otherwise, it is enforced if the ancestor node exists.

The constraint is further enforced according to the rules in 
Section 8.

7.7.4 max-elements声明

The “max-elements” statement, which is optional, takes as an argument 
a positive integer or the string “unbounded”, which puts a constraint 
on valid list entries. A valid leaf-list or list always has at most 
max-elements entries.

If no “max-elements” statement is present, it defaults to 
“unbounded”.

The “max-elements” constraint is enforced according to the rules in 
Section 8.

7.7.5 ordered-by声明

“ordered-by”声明定义了列表中列表项的顺序是用户定义还是系统自定义。其参数是“system”和“user”中的一个。如果该声明没有出现,默认值是“system”。

如果列表表达的是state date,RPC output parameters,或者notification content,则这个声明会被忽略,因为对以上三种数据,都没有排序的必要。

更多信息可见Section 7.7.1

7.7.5.1 ordered-by system

The entries in the list are sorted according to an unspecified order. 
Thus, an implementation is free to sort the entries in the most 
appropriate order. An implementation SHOULD use the same order for 
the same data, regardless of how the data were created. Using a 
deterministic order will make comparisons possible using simple tools 
like “diff”.

This is the default order.

7.7.5.2 ordered-by user

列表项的排序是用户通过中的特殊XML属性控制的。可见Section 7.7.7

7.7.6 XML映射规则

A leaf-list node is encoded as a series of XML elements. Each 
element’s local name is the leaf-list’s identifier, and its namespace 
is the module’s XML namespace (see Section 7.1.3).

The value of each leaf-list entry is encoded to XML according to the 
type, and sent as character data in the element.

The XML elements representing leaf-list entries MUST appear in the 
order specified by the user if the leaf-list is “ordered-by user”; 
otherwise, the order is implementation-dependent. The XML elements 
representing leaf-list entries MAY be interleaved with other sibling 
elements, unless the leaf-list defines RPC input or output 
parameters.

See Section 7.7.8 for an example.

7.7.7 NETCONF 操作

Leaf-list entries can be created and deleted, but not modified, 
through , by using the “operation” attribute in the 
leaf-list entry’s XML element.

In an “ordered-by user” leaf-list, the attributes “insert” and 
“value” in the YANG XML namespace (Section 5.3.1) can be used to 
control where in the leaf-list the entry is inserted. These can be 
used during “create” operations to insert a new leaf-list entry, or 
during “merge” or “replace” operations to insert a new leaf-list 
entry or move an existing one.

The “insert” attribute can take the values “first”, “last”, “before”, 
and “after”. If the value is “before” or “after”, the “value” 
attribute MUST also be used to specify an existing entry in the leaf- 
list.

If no “insert” attribute is present in the “create” operation, it 
defaults to “last”.

If several entries in an “ordered-by user” leaf-list are modified in 
the same request, the entries are modified one at the 
time, in the order of the XML elements in the request.

In a , or an with a “replace” operation 
that covers the entire leaf-list, the leaf-list order is the same as 
the order of the XML elements in the request.

When a NETCONF server processes an request, the 
elements of procedure for a leaf-list node are:

  If the operation is "merge" or "replace", the leaf-list entry is
  created if it does not exist.

  If the operation is "create", the leaf-list entry is created if it
  does not exist.  If the leaf-list entry already exists, a
  "data-exists" error is returned.

  If the operation is "delete", the entry is deleted from the leaf-
  list if it exists.  If the leaf-list entry does not exist, a
  "data-missing" error is returned.   
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

7.7.8 使用用例

 leaf-list allow-user  {
     type string;
     description "A list of user name patterns to allow";
 }
  • 1
  • 2
  • 3
  • 4
  • 5

对应的XML实例:

 <allow-user>alice</allow-user>
 <allow-user>bob</allow-user>
  • 1
  • 2
  • 3

为了在列表中增加一个新元素,使用中的操作“merge”:

 <rpc message-id="101"
      xmlns="urn:ietf:params:xml:ns:netconf:base:1.0"
      xmlns:nc="urn:ietf:params:xml:ns:netconf:base:1.0">
   <edit-config>
     <target>
       <running/>
     </target>
     <config>
       <system xmlns="http://example.com/schema/config">
         <services>
           <ssh>
             <allow-user>eric</allow-user>
           </ssh>
         </services>
       </system>
     </config>
   </edit-config>
 </rpc>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19

给定下面的用户排序的例子:

 leaf-list cipher  {
     type string;
     ordered-by user;
     description "A list of ciphers";
 }                
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

下面的语句是要在“3des-cbc”后面插入一条新的cipher “blowfish-cbc”:

 <rpc message-id="101"
      xmlns="urn:ietf:params:xml:ns:netconf:base:1.0"
      xmlns:nc="urn:ietf:params:xml:ns:netconf:base:1.0"
      xmlns:yang="urn:ietf:params:xml:ns:yang:1">
   <edit-config>
     <target>
       <running/>
     </target>
     <config>
       <system xmlns="http://example.com/schema/config">
         <services>
           <ssh>
             <cipher nc:operation="create"
                     yang:insert="after"
                     yang:value="3des-cbc">blowfish-cbc</cipher>
           </ssh>
         </services>
       </system>
     </config>
   </edit-config>
 </rpc>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22

7.8 list声明

“list”声明被用来定义一个schema tree中的内部数据节点(interior data node)。一个list node在data tree中可能有多个实例存在。每个这样的实例都被认为是一个列表项。“list”声明有一个参数,是identifier,后面跟着描述更详细信息的一块substatements。

一个列表项是由该列表的keys的值唯一指定的,前提是keys存在。

7.8.1 list的substatements

             +--------------+---------+-------------+
             | substatement | section | cardinality |
             +--------------+---------+-------------+
             | anyxml       | 7.10    | 0..n        |
             | choice       | 7.9     | 0..n        |
             | config       | 7.19.1  | 0..1        |
             | container    | 7.5     | 0..n        |
             | description  | 7.19.3  | 0..1        |
             | grouping     | 7.11    | 0..n        |
             | if-feature   | 7.18.2  | 0..n        |
             | key          | 7.8.2   | 0..1        |
             | leaf         | 7.6     | 0..n        |
             | leaf-list    | 7.7     | 0..n        |
             | list         | 7.8     | 0..n        |
             | max-elements | 7.7.4   | 0..1        |
             | min-elements | 7.7.3   | 0..1        |
             | must         | 7.5.3   | 0..n        |
             | ordered-by   | 7.7.5   | 0..1        |
             | reference    | 7.19.4  | 0..1        |
             | status       | 7.19.2  | 0..1        |
             | typedef      | 7.3     | 0..n        |
             | unique       | 7.8.3   | 0..n        |
             | uses         | 7.12    | 0..n        |
             | when         | 7.19.5  | 0..1        |
             +--------------+---------+-------------+
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26

7.8.2 list的key声明

“key”声明,如果该list表示的是configuration信息,则 MUST 存在;其他情况下,则MAY 存在。有一个字符串的参数,该字符串是一个用空格符作为分隔符的这个list中的leaf的identifiers的列表。在key中,一个leaf的identifier MUST NOT 出现超过一次。每个这样的leaf identifier MUST 是该list的child leaf中的一个。这个leafs能直接在list的substatements中定义,也可以在list中的groupings里使用。

在key中指定的所有leafs的值的组合唯一确定了一个列表项(感觉有点类似于数据库中的联合主键)。当一个列表项被创建时,所有的key leafs都 MUST 被赋值。这样一来,在key leafs中的任何默认值都会被忽略。key leafs中的任何mandatory statement都会被忽略。

不太明白啥意思。附上原文:Thus, any default values in the key leafs or their types are ignored. It also implies that any mandatory statement in the key leafs are ignored.

作为key的一部分的一个leaf能够是任何内置类型或者派生类型,但是 MUST NOT 是内置类型“empty”。

All key leafs in a list MUST have the same value for their “config” as the list itself.

key的字符串的语法是Section 12中的“key-arg”规则定义的。

7.8.3 list的unique声明

“unique”声明被用来对有效的列表项施加约束的。它有一个参数,是一个字符串。该字符串中包含了schema node identifiers的以空格为分隔符的列表,这些ids MUST 是descendant form的形式(见Section 12中的“descendant-schema-nodeid”规则)。每个这样的schema node identifier MUST 指向一个leaf。

如果被引用的leafs中有一个是configuration data,则所有被引用的leafs都 MUST 表示configuration data。

“unique”约束指定:所有在参数字符串中指定的leafs的实例的值,包括那些使用默认值的leafs,都 MUST 在所有列表项实例中保证唯一。这个约束根据Section 8的规则强制执行。

“unique”字符串语法由Section 12中的“unique-arg”语法正式定义。

7.8.3.1 使用用例

假设有下面的list定义:

 list server {
     key "name";
     unique "ip port";
     leaf name {
         type string;
     }
     leaf ip {
         type inet:ip-address;
     }
     leaf port {
         type inet:port-number;
     }
 }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

则下面两个configuration是无效的:

 <server>
   <name>smtp</name>
   <ip>192.0.2.1</ip>
   <port>25</port>
 </server>

 <server>
   <name>http</name>
   <ip>192.0.2.1</ip>
   <port>25</port>
 </server>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

下面的configuration是有效的,因为“http”和“ftp”的list表项没有实现所有被unique引用的leafs,因此在“unique”约束执行检查的时候不会被约束掉:

 <server>
   <name>smtp</name>
   <ip>192.0.2.1</ip>
   <port>25</port>
 </server>

 <server>
   <name>http</name>
   <ip>192.0.2.1</ip>
 </server>

 <server>
   <name>ftp</name>
   <ip>192.0.2.1</ip>
 </server>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

7.8.4 list的child node statements

list的child nodes可以是”container”, “leaf”, “list”, “leaf-list”, “uses”, 
“choice”, 以及 “anyxml”。

7.8.5 XML映射规则

A list is encoded as a series of XML elements, one for each entry in 
the list. Each element’s local name is the list’s identifier, and 
its namespace is the module’s XML namespace (see Section 7.1.3).

The list’s key nodes are encoded as subelements to the list’s 
identifier element, in the same order as they are defined within the 
“key” statement.

The rest of the list’s child nodes are encoded as subelements to the 
list element, after the keys. If the list defines RPC input or 
output parameters, the subelements are encoded in the same order as 
they are defined within the “list” statement. Otherwise, the 
subelements are encoded in any order.

The XML elements representing list entries MUST appear in the order 
specified by the user if the list is “ordered-by user”, otherwise the 
order is implementation-dependent. The XML elements representing 
list entries MAY be interleaved with other sibling elements, unless 
the list defines RPC input or output parameters.

7.8.6 NETCONF 操作

List entries can be created, deleted, replaced, and modified through 
, by using the “operation” attribute in the list’s XML 
element. In each case, the values of all keys are used to uniquely 
identify a list entry. If all keys are not specified for a list 
entry, a “missing-element” error is returned.

In an “ordered-by user” list, the attributes “insert” and “key” in 
the YANG XML namespace (Section 5.3.1) can be used to control where 
in the list the entry is inserted. These can be used during “create” 
operations to insert a new list entry, or during “merge” or “replace” 
operations to insert a new list entry or move an existing one.

The “insert” attribute can take the values “first”, “last”, “before”, 
and “after”. If the value is “before” or “after”, the “key” 
attribute MUST also be used, to specify an existing element in the 
list. The value of the “key” attribute is the key predicates of the 
full instance identifier (see Section 9.13) for the list entry.

If no “insert” attribute is present in the “create” operation, it 
defaults to “last”.

If several entries in an “ordered-by user” list are modified in the 
same request, the entries are modified one at the time, 
in the order of the XML elements in the request.

In a , or an with a “replace” operation 
that covers the entire list, the list entry order is the same as the 
order of the XML elements in the request.

When a NETCONF server processes an request, the 
elements of procedure for a list node are:

  If the operation is "merge" or "replace", the list entry is
  created if it does not exist.  If the list entry already exists
  and the "insert" and "key" attributes are present, the list entry
  is moved according to the values of the "insert" and "key"
  attributes.  If the list entry exists and the "insert" and "key"
  attributes are not present, the list entry is not moved.

  If the operation is "create", the list entry is created if it does
  not exist.  If the list entry already exists, a "data-exists"
  error is returned.

  If the operation is "delete", the entry is deleted from the list
  if it exists.  If the list entry does not exist, a "data-missing"
  error is returned.
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

7.8.7 使用用例

给定下面的一个list:

 list user {
     key "name";
     config true;
     description "This is a list of users in the system.";

     leaf name {
         type string;
     }
     leaf type {
         type string;
     }
     leaf full-name {
         type string;
     }
 }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

对应的XML实例:

 <user>
   <name>fred</name>
   <type>admin</type>
   <full-name>Fred Flintstone</full-name>
 </user>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

创建一个新用户“barney”:

     <rpc message-id="101"
          xmlns="urn:ietf:params:xml:ns:netconf:base:1.0"
          xmlns:nc="urn:ietf:params:xml:ns:netconf:base:1.0">
       <edit-config>
         <target>
           <running/>
         </target>
         <config>
           <system xmlns="http://example.com/schema/config">
             <user nc:operation="create">
               <name>barney</name>
               <type>admin</type>
               <full-name>Barney Rubble</full-name>
             </user>
           </system>
         </config>
       </edit-config>
     </rpc>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18

改变“fred”的类型为“superuser”:

     <rpc message-id="101"
          xmlns="urn:ietf:params:xml:ns:netconf:base:1.0"
          xmlns:nc="urn:ietf:params:xml:ns:netconf:base:1.0">
       <edit-config>
         <target>
           <running/>
         </target>
         <config>
           <system xmlns="http://example.com/schema/config">
             <user>
               <name>fred</name>
               <type>superuser</type>
             </user>
           </system>
         </config>
       </edit-config>
     </rpc>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17

给定下面的ordered-by user list:

 list user {
     description "This is a list of users in the system.";
     ordered-by user;
     config true;

     key "name";

     leaf name {
         type string;
     }
     leaf type {
         type string;
     }
     leaf full-name {
         type string;
     }
 }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18

下面的xml表示在用户“fred”后面插入一个新用户“barney”:

     <rpc message-id="101"
          xmlns="urn:ietf:params:xml:ns:netconf:base:1.0"
          xmlns:nc="urn:ietf:params:xml:ns:netconf:base:1.0"
          xmlns:yang="urn:ietf:params:xml:ns:yang:1">
       <edit-config>
         <target>
           <running/>
         </target>
         <config>
           <system xmlns="http://example.com/schema/config"
                xmlns:ex="http://example.com/schema/config">
             <user nc:operation="create"
                   yang:insert="after"
                   yang:key="[ex:name='fred']">
               <name>barney</name>
               <type>admin</type>
               <full-name>Barney Rubble</full-name>
             </user>
           </system>
         </config>
       </edit-config>
     </rpc>     
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22

下面的语句是将用户“barney”移到用户“fred”前面:

     <rpc message-id="101"
          xmlns="urn:ietf:params:xml:ns:netconf:base:1.0"
          xmlns:nc="urn:ietf:params:xml:ns:netconf:base:1.0"
          xmlns:yang="urn:ietf:params:xml:ns:yang:1">
       <edit-config>
         <target>
           <running/>
         </target>
         <config>
           <system xmlns="http://example.com/schema/config"
                xmlns:ex="http://example.com/schema/config">
             <user nc:operation="merge"
                   yang:insert="before"
                   yang:key="[ex:name='fred']">
               <name>barney</name>
             </user>
           </system>
         </config>
       </edit-config>
     </rpc>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20

7.9 choice声明

“choice”声明定义了可选项的一个集合,同时只能有其中的一个存在。其参数是一个identifier,后面跟着描述具体信息的一块substatements。这个identifier被用来在schema tree中标识这个choice node。choice node不会在data tree中存在。

一个choice由多个branches组成,这些branches是用“case” substatement定义的。每个branch都包含多个child nodes。在这些branches中同时最多只能有其中一个branch的nodes能够存在。

更多信息可见Section 8.3.2

7.9.1 choice的substatements

             +--------------+---------+-------------+
             | substatement | section | cardinality |
             +--------------+---------+-------------+
             | anyxml       | 7.10    | 0..n        |
             | case         | 7.9.2   | 0..n        |
             | config       | 7.19.1  | 0..1        |
             | container    | 7.5     | 0..n        |
             | default      | 7.9.3   | 0..1        |
             | description  | 7.19.3  | 0..1        |
             | if-feature   | 7.18.2  | 0..n        |
             | leaf         | 7.6     | 0..n        |
             | leaf-list    | 7.7     | 0..n        |
             | list         | 7.8     | 0..n        |
             | mandatory    | 7.9.4   | 0..1        |
             | reference    | 7.19.4  | 0..1        |
             | status       | 7.19.2  | 0..1        |
             | when         | 7.19.5  | 0..1        |
             +--------------+---------+-------------+
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19

7.9.2 choice的case声明

“case”声明被用来定义choice的branches。它有一个参数,是identifier,后面跟着描述详细信息的一块substatements。

这个identifier被用来在schema tree中标识这个case node。在data tree中不存在case node。

在一个“case”声明中,其child nodes可以用“anyxml”,“choice”, “container”,“leaf”, “list”,“leaf-list”,以及“uses”声明。所有child nodes的identifiers都 MUST 在该choice的所有cases中保持唯一。例如,下面的定义就是非法的:

 choice interface-type {     // This example is illegal YANG
     case a {
         leaf ethernet { ... }
     }
     case b {
         container ethernet { ...}
     }
 }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

YANG中有一种简略的写法,当branch中包含单个的“anyxml”,“container”,“leaf”,“list”或者“leaf-list”声明的时候,“case”声明可以省略。这种情况下,这个case的identifier和其中的声明的identifier一样。下面是一个例子:

 choice interface-type {
     container ethernet { ... }
 }
  • 1
  • 2
  • 3
  • 4

等价于:

 choice interface-type {
     case ethernet {
         container ethernet { ... }
     }
 }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

在一个choice中,case identifier MUST 是唯一的。

7.9.2.1 case的substatements

             +--------------+---------+-------------+
             | substatement | section | cardinality |
             +--------------+---------+-------------+
             | anyxml       | 7.10    | 0..n        |
             | choice       | 7.9     | 0..n        |
             | container    | 7.5     | 0..n        |
             | description  | 7.19.3  | 0..1        |
             | if-feature   | 7.18.2  | 0..n        |
             | leaf         | 7.6     | 0..n        |
             | leaf-list    | 7.7     | 0..n        |
             | list         | 7.8     | 0..n        |
             | reference    | 7.19.4  | 0..1        |
             | status       | 7.19.2  | 0..1        |
             | uses         | 7.12    | 0..n        |
             | when         | 7.19.5  | 0..1        |
             +--------------+---------+-------------+
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17

7.9.3 choice的default声明

The “default” statement indicates if a case should be considered as 
the default if no child nodes from any of the choice’s cases exist. 
The argument is the identifier of the “case” statement. If the 
“default” statement is missing, there is no default case.

当“mandatory”的值为true时,“default”声明 MUST 不能出现。

The default case is only important when considering the default 
values of nodes under the cases. The default values for nodes under 
the default case are used if none of the nodes under any of the cases 
are present.

There MUST NOT be any mandatory nodes (Section 3.1) directly under 
the default case.

Default values for child nodes under a case are only used if one of 
the nodes under that case is present, or if that case is the default 
case. If none of the nodes under a case are present and the case is 
not the default case, the default values of the cases’ child nodes 
are ignored.

In this example, the choice defaults to “interval”, and the default 
value will be used if none of “daily”, “time-of-day”, or “manual” are 
present. If “daily” is present, the default value for “time-of-day” 
will be used.

 container transfer {
     choice how {
         default interval;
         case interval {
             leaf interval {
                 type uint16;
                 default 30;
                 units minutes;
             }
         }
         case daily {
             leaf daily {
                 type empty;
             }
             leaf time-of-day {
                 type string;
                 units 24-hour-clock;
                 default 1am;
             }
         }
         case manual {
             leaf manual {
                 type empty;
             }
         }
     }
 }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28

7.9.4 choice的mandatory声明

“mandatory”声明,是可选的,其参数是值为“true”或“false”的string,作用是对有效的数据施加一种约束。如果取值为“true”,则说明choice的case branches中特定的某个branch中的至少一个node MUST 存在。

如果没有指定,默认值是“false”。

The behavior of the constraint depends on the type of the choice’s 
closest ancestor node in the schema tree which is not a non-presence 
container (see Section 7.5.1):

o If this ancestor is a case node, the constraint is enforced if any 
other node from the case exists.

o Otherwise, it is enforced if the ancestor node exists.

The constraint is further enforced according to the rules in 
Section 8.

7.9.5 XML映射规则

choice和case nodes在XML中不可见。

The child nodes of the selected “case” statement MUST be encoded in 
the same order as they are defined in the “case” statement if they 
are part of an RPC input or output parameter definition. Otherwise, 
the subelements are encoded in any order.

7.9.6 NETCONF 操作

Since only one of the choice’s cases can be valid at any time, the 
creation of a node from one case implicitly deletes all nodes from 
all other cases. If an operation creates a node from a 
case, the NETCONF server will delete any existing nodes that are 
defined in other cases inside the choice.

7.9.7 使用用例

给定下面的choice:

 container protocol {
     choice name {
         case a {
             leaf udp {
                 type empty;
             }
         }
         case b {
             leaf tcp {
                type empty;
             }
         }
     }
 }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

对应的XML实例可以是:

 <protocol>
   <tcp/>
 </protocol>
  • 1
  • 2
  • 3
  • 4

将protocol从tcp改成udp:

     <rpc message-id="101"
          xmlns="urn:ietf:params:xml:ns:netconf:base:1.0"
          xmlns:nc="urn:ietf:params:xml:ns:netconf:base:1.0">
       <edit-config>
         <target>
           <running/>
         </target>
         <config>
           <system xmlns="http://example.com/schema/config">
             <protocol>
               <udp nc:operation="create"/>
             </protocol>
           </system>
         </config>
       </edit-config>
     </rpc>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

7.10 anyxml声明

“anyxml”声明定义了schema tree的一个内部节点(interior node)。它有一个参数,是一个identifier,后面跟着描述详细信息的一块substatements。

“anyxml”声明被用来标识XML中未知的文本块。在XML上没有施加任何restrictions。这是相当有用的一点,比如说,在RPC的replies中。给出一个例子,在操作中的参数。

一个anyxml节点不能被扩展(augmented),可见Section 7.15。

由于对“anyxml”的使用会限制对内容的操控,所以 RECOMMENDED “anyxml”声明不要被用来表示configuration data。

在data tree中,一个anyxml node只能存在于0个或1个实例中。

上面这句话没明白,是说在data tree中,只能有一个anyxml的实现吗?原文如下:_An anyxml node exists in zero or one instances in the data tree. 
_

7.10.1 anyxml的substatements

             +--------------+---------+-------------+
             | substatement | section | cardinality |
             +--------------+---------+-------------+
             | config       | 7.19.1  | 0..1        |
             | description  | 7.19.3  | 0..1        |
             | if-feature   | 7.18.2  | 0..n        |
             | mandatory    | 7.6.5   | 0..1        |
             | must         | 7.5.3   | 0..n        |
             | reference    | 7.19.4  | 0..1        |
             | status       | 7.19.2  | 0..1        |
             | when         | 7.19.5  | 0..1        |
             +--------------+---------+-------------+
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

7.10.2 XML映射规则

一个anyxml node会被编码为一个XML element。这个element的local name就是这个anyxml的identifier,它的namespace就是module的XML namespace。anyxml node的值会被编码为这个element的XML内容。

需要明白,在编码中使用到的任何前缀对于每个实例来说都是本地有效的。这意味着,在不同的实现中,同一个XML会被编码为不同的东西。(Note that any prefixes used in the encoding are local to each instance encoding. This means that the same XML may be encoded differently by different implementations.

7.10.3 NETCONF 操作

一个anyxml node被认为是一块不透明的数据块(因为不知道里面什么内容,无法解析)。这个数据块只能整个被替换。

在anyxml node的subelements中出现的任何“operation”属性都会被NETCONF服务端忽略,不作处理。

When a NETCONF server processes an request, the 
elements of procedure for the anyxml node are:

  If the operation is "merge" or "replace", the node is created if
  it does not exist, and its value is set to the XML content of the
  anyxml node found in the XML RPC data.

  If the operation is "create", the node is created if it does not
  exist, and its value is set to the XML content of the anyxml node
  found in the XML RPC data.  If the node already exists, a
  "data-exists" error is returned.

  If the operation is "delete", the node is deleted if it exists.
  If the node does not exist, a "data-missing" error is returned.
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

7.10.4 使用用例

给定下面的“anyxml”声明:

 anyxml data;
  • 1
  • 2

下面是同一个anyxml值的两种不同的编码:

 <data xmlns:if="http://example.com/ns/interface">
   <if:interface>
     <if:ifIndex>1</if:ifIndex>
   </if:interface>
 </data>

 <data>
   <interface xmlns="http://example.com/ns/interface">
     <ifIndex>1</ifIndex>
   </interface>
 </data>          
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

7.11 grouping声明

“grouping”声明被用来定义可重用的block of nodes,可能会在module内部被使用,在包含它的modules中使用,或者导入它的其它modules中被使用。它有一个参数,是一个identifier,后面跟着描述更详细信息的一块substatements。

“grouping”声明不是一个data 定义的声明,在schema tree中不会定义任何nodes。

一个grouping类似于常见编程语言中的“structure”或者“record”。

一旦一个grouping被定义,它就能通过“uses”声明被引用(见Section 7.12)。一个grouping MUST NOT 引用它自己,也不能间接通过其它的groupings的引用链引用到自己。

如果grouping定义在YANG module或submodule的top level,grouping的identifier就MUST 在module内是唯一的。

grouping的作用不仅仅是一种文本替换机制,而且将某些nodes整合到了一个集合中。grouping中的identifiers会放到grouping定义的地方进行范围的界定,而不是放到其被使用的地方。而prefix mappings,type names,grouping names,以及extension usage会在“grouping”声明出现的垂直结构中进行评估。以extensions为例,这意味着extensions会被应用到grouping node,而不是uses node。

没想明白为什么会放到grouping定义的地方进行scope的界定,如果这样的话,被引用的地方就有可能出现identifiers的冲突了吧?

7.11.1 grouping的substatements

             +--------------+---------+-------------+
             | substatement | section | cardinality |
             +--------------+---------+-------------+
             | anyxml       | 7.10    | 0..n        |
             | choice       | 7.9     | 0..n        |
             | container    | 7.5     | 0..n        |
             | description  | 7.19.3  | 0..1        |
             | grouping     | 7.11    | 0..n        |
             | leaf         | 7.6     | 0..n        |
             | leaf-list    | 7.7     | 0..n        |
             | list         | 7.8     | 0..n        |
             | reference    | 7.19.4  | 0..1        |
             | status       | 7.19.2  | 0..1        |
             | typedef      | 7.3     | 0..n        |
             | uses         | 7.12    | 0..n        |
             +--------------+---------+-------------+
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17

7.11.2 使用用例

 import ietf-inet-types {
     prefix "inet";
 }

 grouping endpoint {
     description "A reusable endpoint group.";
     leaf ip {
         type inet:ip-address;
     }
     leaf port {
         type inet:port-number;
     }
 }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

7.12 uses声明

“uses”声明被用来引用一个“grouping”定义。它有一个参数,就是所引用的grouping的名字。

“uses”的作用就是它所引用的grouping所包含的nodes会被复制到当前的schema tree中,并且后面会根据“refine”和“augment”声明而更新。

暂时还不知道refine和augment是啥?

在grouping中定义的identifiers不回绑定到一个在“grouping”声明内部没有出现的namespace,除非这个grouping的内容通过“uses”声明被增加到对应的schema tree中,这种情况下,它们就会被绑定到当前的module中。

以防误解,附上原文:The identifiers defined in the grouping are not bound to a namespace until the contents of the grouping are added to the schema tree via a “uses” statement that does not appear inside a “grouping” statement, at which point they are bound to the namespace of the current module.

7.12.1 uses的substatements

             +--------------+---------+-------------+
             | substatement | section | cardinality |
             +--------------+---------+-------------+
             | augment      | 7.15    | 0..1        |
             | description  | 7.19.3  | 0..1        |
             | if-feature   | 7.18.2  | 0..n        |
             | refine       | 7.12.2  | 0..1        |
             | reference    | 7.19.4  | 0..1        |
             | status       | 7.19.2  | 0..1        |
             | when         | 7.19.5  | 0..1        |
             +--------------+---------+-------------+
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

7.12.2 refine声明

在grouping中的每个node的某些属性都能通过“refine”声明refined。其参数是grouping中的某个node的identifier。这个node被称为这个refine的target node。如果grouping中的一个node在“refine”声明中没有作为target node出现,它就不会被refined,因此被引用的时候就按照它在grouping中定义的那样被引用。

参数字符串是一个descendant schema node identifier(见Section 6.5)。

可以进行下面的refinements:

  • 一个leaf或choice node可能通过“refine”获得一个默认值,或者本来就有一个默认值,被新的默认值替代了。
  • 任何node都能通过它获得应用场景下的“description”字符串。
  • 任何node都能通过它获得应用场景下的“reference”字符串。
  • 任何node都能通过它获得一个不同的“config”声明。
  • 一个leaf,anyxml,或者choice node都能通过它获得一个不同的“mandatory”声明。
  • 一个container node能通过它获得一个“presence”声明。表示一个container是否有实际意义
  • 一个leaf,leaf-list,list,container或anyxml node能通过它获得额外的“must”表达式。
  • 一个leaf-list或list node能通过它获得一个不同的“min-elements”或“max-elements”声明。

refined这个词在词典中的意思是“精炼的”。不过给我的感觉更像是redefined或者modified。是为了适应grouping的使用场景对其做的一些修改。

7.12.3 XML 映射规则

在grouping中的每个node在编码时表现就像它是被内联进去的,即便它是其它XML namespace的另一个module中导入的。(简单来说,就按照C++里面的inline关键词理解就行了

7.12.4 使用用例

为了在其它module中定义的HTTP server中使用Section 7.11.2中定义的“endpoint” grouping,我们可以这么写:

 import acme-system {
     prefix "acme";
 }

 container http-server {
     leaf name {
         type string;
     }
     uses acme:endpoint;
 }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

对应的XML实例例子有:

     <http-server>
       <name>extern-web</name>
       <ip>192.0.2.1</ip>
       <port>80</port>
     </http-server>
  • 1
  • 2
  • 3
  • 4
  • 5

如果端口80应该是HTTP Server的默认端口,则可以这么写:

 container http-server {
     leaf name {
         type string;
     }
     uses acme:endpoint {
         refine port {
             default 80;
         }
     }
 }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

如果我们要定义一个servers的list,其中每个server都将ip和port作为keys,我们可以这么写:

 list server {
     key "ip port";
     leaf name {
         type string;
     }
     uses acme:endpoint;
 }   
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

下面是一个错误用例:

 container http-server {
     uses acme:endpoint;
     leaf ip {          // illegal - same identifier "ip" used twice
         type string;
     }
 }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

7.13 rpc声明

“rpc”声明被用来定义一个NETCONF RPC操作。它有一个参数,是一个identifier,后面跟着描述详细信息的一块substatements。这个参数是RPC的名字,在XML中作为 element的element名字,as designated by the substitution group “rpcOperation” in RFC4741

“rpc”声明在schema tree中定义了一个rpc node。在这个rpc node之下,也会定义两个schema node,一个名字叫“input”,一个叫“output”。node “input”和“output”都是定义在module的namespace中的。

7.13.1 rpc的substatements

             +--------------+---------+-------------+
             | substatement | section | cardinality |
             +--------------+---------+-------------+
             | description  | 7.19.3  | 0..1        |
             | grouping     | 7.11    | 0..n        |
             | if-feature   | 7.18.2  | 0..n        |
             | input        | 7.13.2  | 0..1        |
             | output       | 7.13.3  | 0..1        |
             | reference    | 7.19.4  | 0..1        |
             | status       | 7.19.2  | 0..1        |
             | typedef      | 7.3     | 0..n        |
             +--------------+---------+-------------+
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

7.13.2 input声明

“input”声明,是可选的,被用来定义RPC操作的输入参数。它没有参数。“input”的substatements直接定义在input node之下。

如果在input tree中的一个leaf的“mandatory”声明的值为“true”,这个leaf MUST 在NETCONF RPC调用时出现,否则,服务端 MUST 返回一个“missing-element”的错误。

如果一个在input tree中的leaf有默认值,则NETCONF服务器 MUST 在和如Section 7.6.1 相同的场景下使用这个值。在这些场景下,服务器 MUST 表现得好像在NETCONF RPC 调用中这个leaf本身就存在,并且其值为默认值。

如果一个“config”声明出现在input tree中的任何node中,它都不会被处理。

如果任何node的“when”声明的约束都被评估为false,则这个node MUST NOT 出现在input tree中。

7.13.2.1 input的substatements

             +--------------+---------+-------------+
             | substatement | section | cardinality |
             +--------------+---------+-------------+
             | anyxml       | 7.10    | 0..n        |
             | choice       | 7.9     | 0..n        |
             | container    | 7.5     | 0..n        |
             | grouping     | 7.11    | 0..n        |
             | leaf         | 7.6     | 0..n        |
             | leaf-list    | 7.7     | 0..n        |
             | list         | 7.8     | 0..n        |
             | typedef      | 7.3     | 0..n        |
             | uses         | 7.12    | 0..n        |
             +--------------+---------+-------------+
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

7.13.3 output声明

“output”声明,是可选的,被用来定义RPC操作中的输出参数。它没有参数。“output”的substatements直接定义在其后。

如果output tree中的一个leaf的“mandatory”声明的值为“true”,则这个leaf MUST 出现在NETCONF RPC reply中。

如果output tree中的一个leaf有一个默认值,则NETCONF 客户端 MUST 在和Section 7.6.1描述的场景相同的情况下使用这个值。在这些情况下,客户端 MUST 表现得好像NETCONF RPC reply中本来就有这个leaf,并且其值就是默认值一样。

如果一个“config”声明出现在output tree中的任何node中,则这个“config”声明不会被处理,会被忽略。

如果任何node中有一个“when”声明约束,并且评估结果为false,则这个node MUST NOT 出现在output tree中。

7.13.3.1 output的substatements

             +--------------+---------+-------------+
             | substatement | section | cardinality |
             +--------------+---------+-------------+
             | anyxml       | 7.10    | 0..n        |
             | choice       | 7.9     | 0..n        |
             | container    | 7.5     | 0..n        |
             | grouping     | 7.11    | 0..n        |
             | leaf         | 7.6     | 0..n        |
             | leaf-list    | 7.7     | 0..n        |
             | list         | 7.8     | 0..n        |
             | typedef      | 7.3     | 0..n        |
             | uses         | 7.12    | 0..n        |
             +--------------+---------+-------------+
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

7.13.4 XML映射规则

一个rpc node会被编码为【RFC4741】中定义的 element的child XML element。这个element的local name就是rpc的identifier,它的namespace就是rpc node所在module的XML namespace。

input参数会被编码为rpc node的XML element的child XML elements,其排列顺序和“input” statement中定义的顺序一致。

如果RPC 操作的调用成功,并且没有output参数返回,则会仅仅包含一个简单的 element。如果output参数有返回,它们会被编码为 element的child elements,其顺序和“output”声明中定义的顺序一致。

7.13.5 使用用例

下面的例子定义了一个RPC操作:

 module rock {
     namespace "http://example.net/rock";
     prefix "rock";

     rpc rock-the-house {
         input {
             leaf zip-code {
                 type string;
             }
         }
     }
 }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

对应的完整的rpc和rpc-reply的XML实例为:

 <rpc message-id="101"
      xmlns="urn:ietf:params:xml:ns:netconf:base:1.0">
   <rock-the-house xmlns="http://example.net/rock">
     <zip-code>27606-0100</zip-code>
   </rock-the-house>
 </rpc>

 <rpc-reply message-id="101"
            xmlns="urn:ietf:params:xml:ns:netconf:base:1.0">
   <ok/>
 </rpc-reply>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

7.14 notification声明

“notification”声明被用来定义NETCONF的notification。它有一个参数,是一个identifier,后面跟着描述更详细信息的一块substatements。“notification”声明在schema tree中定义了一个notification node。

如果notification tree中的一个leaf有值为true的“mandatory”声明,这个leaf MUST 在NETCONF的notification中出现。

如果notification tree中的一个leaf有默认值,则NETCONF 客户端 MUST 在和Section 7.6.1描述的场景相同的情况下使用这个值。在这些情况下,客户端 MUST 表现得好像NETCONF notification中本来就有这个leaf,并且其值就是默认值一样。

如果“config”声明出现在notification tree中的任何一个node中,则该声明会被忽略。

7.14.1 notification的substatements

             +--------------+---------+-------------+
             | substatement | section | cardinality |
             +--------------+---------+-------------+
             | anyxml       | 7.10    | 0..n        |
             | choice       | 7.9     | 0..n        |
             | container    | 7.5     | 0..n        |
             | description  | 7.19.3  | 0..1        |
             | grouping     | 7.11    | 0..n        |
             | if-feature   | 7.18.2  | 0..n        |
             | leaf         | 7.6     | 0..n        |
             | leaf-list    | 7.7     | 0..n        |
             | list         | 7.8     | 0..n        |
             | reference    | 7.19.4  | 0..1        |
             | status       | 7.19.2  | 0..1        |
             | typedef      | 7.3     | 0..n        |
             | uses         | 7.12    | 0..n        |
             +--------------+---------+-------------+
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18

7.14.2 XML映射规则

一个notification node会作为【RFC5277】中定义的NETCONF Event Notifications对应的 element的child XML element存在。这个element的local name就是notification的identifier,它的namespace就是notification所在的module的XML namespace。

7.14.3 使用用例

下面的例子定义了一个notification:

 module event {

     namespace "http://example.com/event";
     prefix "ev";

     notification event {
         leaf event-class {
             type string;
         }
         anyxml reporting-entity;
         leaf severity {
             type string;
         }
     }
 }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

完整的notification的对应的XML实例为:

 <notification
   xmlns="urn:ietf:params:xml:ns:netconf:notification:1.0">
   <eventTime>2008-07-08T00:01:00Z</eventTime>
   <event xmlns="http://example.com/event">
     <event-class>fault</event-class>
     <reporting-entity>
       <card>Ethernet0</card>
     </reporting-entity>
     <severity>major</severity>
   </event>
 </notification>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

7.15 augment声明

“augment”声明允许将一个module或submodule增加到另外一个module定义的schema tree中,或者增加到当前module以及它的submodules,或者增加到使用“uses”声明定义的grouping所引用的nodes中去。其参数是一个string,标识了一个node在schema tree中的位置。这个节点称为augment的target node。这个target node MUST container,list,choice,case,input,output或者notification node的一种。在该声明的substatements中定义的nodes会被augmented到target node中去。

augment的参数字符串是一个schema node identifier(见Section 6.5)。如果“augment”声明是module或submodule的一个top level的node, MUST 在schema node identifier中使用absolute form(见Section 12中的“absolute-schema-nodeid”)。如果“augment”声明是“uses”声明的一个substatement,则 MUST 使用descendant form(见Section 12的“descendant-schema-nodeid”)。

如果target node是一个containet,list,case,input,output或者notification node,则“container”,“leaf”,“list”,“leaf-list”,“uses”以及“choice”声明可以被用在“augment”声明中。

如果target node是一个choice node, 则“case”声明,或者一个case的简写版的声明(见Section 7.9.2)可以被用在“augment”声明中。

如果target node在另外一个module中,则由augmentation增加的nodes MUST NOT 是mandatory nodes(可见Section 3.1).(If the target node is in another module, then nodes added by the augmentation MUST NOT be mandatory nodes (see Section 3.1).

The “augment” statement MUST NOT add multiple nodes with the same name from the same module to the target node.

7.15.1 augment的substatements

             +--------------+---------+-------------+
             | substatement | section | cardinality |
             +--------------+---------+-------------+
             | anyxml       | 7.10    | 0..n        |
             | case         | 7.9.2   | 0..n        |
             | choice       | 7.9     | 0..n        |
             | container    | 7.5     | 0..n        |
             | description  | 7.19.3  | 0..1        |
             | if-feature   | 7.18.2  | 0..n        |
             | leaf         | 7.6     | 0..n        |
             | leaf-list    | 7.7     | 0..n        |
             | list         | 7.8     | 0..n        |
             | reference    | 7.19.4  | 0..1        |
             | status       | 7.19.2  | 0..1        |
             | uses         | 7.12    | 0..n        |
             | when         | 7.19.5  | 0..1        |
             +--------------+---------+-------------+
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18

status这个声明貌似还没见过呢。

7.15.2 XML映射规则

所有“augment”声明中定义的data nodes都会编码成“augment”被指定的那个module对应的XML namespace的XML elements。

当一个node被augmented的时候,augmenting child nodes会被编码为augmented node的subelements,顺序任意。

7.15.3 使用用例

在namespace “http://example.com/schema/interfaces”中,我们有:

 container interfaces {
     list ifEntry {
         key "ifIndex";

         leaf ifIndex {
             type uint32;
         }
         leaf ifDescr {
             type string;
         }
         leaf ifType {
             type iana:IfType;
         }
         leaf ifMtu {
             type int32;
         }
     }
 }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19

这里的ifType的类型为 “iana:IfType”。

然后,在namespace “http://example.com/schema/ds0”中,我们有:

 import interface-module {
     prefix "if";
 }
 augment "/if:interfaces/if:ifEntry" {
     when "if:ifType='ds0'";
     leaf ds0ChannelNumber {
         type ChannelNumber;
     }
 }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

对应的XML实例是:

     <interfaces xmlns="http://example.com/schema/interfaces"
                 xmlns:ds0="http://example.com/schema/ds0">
       <ifEntry>
         <ifIndex>1</ifIndex>
         <ifDescr>Flintstone Inc Ethernet A562</ifDescr>
         <ifType>ethernetCsmacd</ifType>
         <ifMtu>1500</ifMtu>
       </ifEntry>
       <ifEntry>
         <ifIndex>2</ifIndex>
         <ifDescr>Flintstone Inc DS0</ifDescr>
         <ifType>ds0</ifType>
         <!-- 类型为ds0的时候,增加了ds0ChannelNumber -->
         <ds0:ds0ChannelNumber>1</ds0:ds0ChannelNumber>
       </ifEntry>
     </interfaces>     
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

另外一个例子中,我们假设有一个在Section 7.9.7中定义的choice。下面的结构能被用来扩展其中的protocol的定义:

 augment /ex:system/ex:protocol/ex:name {
     case c {
         leaf smtp {
             type empty;
         }
     }
 }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

对应的XML实例为:

     <ex:system>
       <ex:protocol>
         <ex:tcp/>
       </ex:protocol>
     </ex:system>
  • 1
  • 2
  • 3
  • 4
  • 5

或者:

     <ex:system>
       <ex:protocol>
         <other:smtp/>
       </ex:protocol>
     </ex:system>
  • 1
  • 2
  • 3
  • 4
  • 5

7.16 identity声明

“identity”声明被用来定义一个新的,全局唯一的,抽象的,没有特定类型的identity。它的唯一目的就是对外宣示它的名字,语义以及存在。一个identity既能够从头开始定义,也能够从一个base identity处继承。identity的参数是一个identifier,就是这个identity的名字。后面跟着描述更具体信息的一块substatements。

内置的数据类型“identityref”(见Section 9.10)能够在一个data model内部被用来引用identities。

7.16.1 identity的substatements

             +--------------+---------+-------------+
             | substatement | section | cardinality |
             +--------------+---------+-------------+
             | base         | 7.16.2  | 0..1        |
             | description  | 7.19.3  | 0..1        |
             | reference    | 7.19.4  | 0..1        |
             | status       | 7.19.2  | 0..1        |
             +--------------+---------+-------------+
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

7.16.2 base声明

“base”声明是可选的,其参数是一个已存在的identity的名字,本次定义的identity就是从它那里继承来的。如果“base”声明没有出现,则这个identity的定义就是从零开始的。

如果在base的名字中有前缀,该前缀会指向定义这个identity的module,或者,如果该前缀正好是local module的前缀,则就指向本module。否则,MUST 指向当前的module或者一个被包含的submodule。

local module 和 current module是有区别的,我日啊,之前一直以为是同样的东西。local表示本地,本地不一定只有current这一个module啊,也可以有其它module。

由于submodules不能包含其父module,所以任何在module中定义的identities,如果需要被submodules引用,则 MUST 定义到某个submodule中去。submodules能够接着引用这个submodule去获取这个identity的定义。

一个identity MUST NOT 引用自己,无论是直接的还是通过其它的identities形成的引用链进行的间接引用。

7.1。3 使用用例

 module crypto-base {
     namespace "http://example.com/crypto-base";
     prefix "crypto";

     identity crypto-alg {
         description
            "Base identity from which all crypto algorithms
             are derived.";
     }
 }

 module des {
     namespace "http://example.com/des";
     prefix "des";

     import "crypto-base" {
         prefix "crypto";
     }

     identity des {
         base "crypto:crypto-alg";
         description "DES crypto algorithm";
     }

     identity des3 {
         base "crypto:crypto-alg";
         description "Triple DES crypto algorithm";
     }
 }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30

按照上面的描述来说,identity在schema tree中存在,在data tree中不存在了?

7.17 extension声明

“extension”声明允许在YANG语言中定义新的声明。这个新的声明的定义可以被其它modules导入和使用。

该声明的参数是一个identifier,表示扩展的新keyword,后面必须跟一块描述详细扩展信息的substatements。“extension”声明的目标就是定义一个keyword,这样它才能被其它modules导入和使用。

extension能像普通的YANG声明一样被使用,声明后面跟一个参数,后面还有可选的一块substatements。新声明的名字是该extension所在的module的前缀,跟上冒号(“:”),再跟上keyword,中间没有空白。extension的substatements是由extension定义的,使用了本标准以外的某些机制。在语法构成上,substatements MUST 是YANG声明,或者也是用“extension”声明定义的新声明。在extensions中使用的YANG声明 MUST 遵循Section 12中定义的语法上的规则。

7.17.1 extension的substatements

             +--------------+---------+-------------+
             | substatement | section | cardinality |
             +--------------+---------+-------------+
             | argument     | 7.17.2  | 0..1        |
             | description  | 7.19.3  | 0..1        |
             | reference    | 7.19.4  | 0..1        |
             | status       | 7.19.2  | 0..1        |
             +--------------+---------+-------------+
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

7.17.2 argument声明

“argument”声明,是可选的,是一个字符串,表示keyword的参数的名字。如果没有argument声明,则keyword在被使用的时候没有参数。

argument的name在YIN mapping中被使用,在那里作为XML attribute或者element name,具体要取决于argument的“yin-element”声明。

7.17.2.1 argument的substatements

             +--------------+----------+-------------+
             | substatement | section  | cardinality |
             +--------------+----------+-------------+
             | yin-element  | 7.17.2.2 | 0..1        |
             +--------------+----------+-------------+
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

7.17.2.2 yin-element声明

“yin-element”声明,是可选的,其参数为“true”或者“false”的字符串。这个声明说明了是否将argument映射到YIN中的一个XML element,或者一个XML attribute(见Section 11)。

如果该声明没有出现,默认值是“false”。

7.17.3 使用用例

首先,定义一个extension:

 module my-extensions {
   ...

   extension c-define {
     description
       "Takes as argument a name string.
       Makes the code generator use the given name in the
       #define.";
     argument "name";
   }
 }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

接着,使用这个extension:

 module my-interfaces {
   ...
   import my-extensions {
     prefix "myext";
   }
   ...

   container interfaces {
     ...
     myext:c-define "MY_INTERFACES";
   }
 }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

7.18 conformance-related声明

这个小姐定义了和一致性(conformance)相关的声明,如Section 5.6中描述的一样。

7.18.1 feature声明

The “feature” statement is used to define a mechanism by which 
portions of the schema are marked as conditional. A feature name is 
defined that can later be referenced using the “if-feature” statement 
(see Section 7.18.2). Schema nodes tagged with a feature are ignored 
by the device unless the device supports the given feature. This 
allows portions of the YANG module to be conditional based on 
conditions on the device. The model can represent the abilities of 
the device within the model, giving a richer model that allows for 
differing device abilities and roles.

The argument to the “feature” statement is the name of the new 
feature, and follows the rules for identifiers in Section 6.2. This 
name is used by the “if-feature” statement to tie the schema nodes to 
the feature.

In this example, a feature called “local-storage” represents the 
ability for a device to store syslog messages on local storage of 
some sort. This feature is used to make the “local-storage-limit” 
leaf conditional on the presence of some sort of local storage. If 
the device does not report that it supports this feature, the 
“local-storage-limit” node is not supported.

 module syslog {
     ...
     feature local-storage {
         description
             "This feature means the device supports local
              storage (memory, flash or disk) that can be used to
              store syslog messages.";
     }

     container syslog {
         leaf local-storage-limit {
             if-feature local-storage;
             type uint64;
             units "kilobyte";
             config false;
             description
                 "The amount of local storage that can be
                  used to hold syslog messages.";
         }
     }
 }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22

The “if-feature” statement can be used in many places within the YANG 
syntax. Definitions tagged with “if-feature” are ignored when the 
device does not support that feature.

A feature MUST NOT reference itself, neither directly nor indirectly 
through a chain of other features.

In order for a device to implement a feature that is dependent on any 
other features (i.e., the feature has one or more “if-feature” sub- 
statements), the device MUST also implement all the dependant 
features.

7.18.1.1 feature的substatements

             +--------------+---------+-------------+
             | substatement | section | cardinality |
             +--------------+---------+-------------+
             | description  | 7.19.3  | 0..1        |
             | if-feature   | 7.18.2  | 0..n        |
             | status       | 7.19.2  | 0..1        |
             | reference    | 7.19.4  | 0..1        |
             +--------------+---------+-------------+
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

7.18.2 if-feature声明

The “if-feature” statement makes its parent statement conditional. 
The argument is the name of a feature, as defined by a “feature” 
statement. The parent statement is implemented by servers that 
support this feature. If a prefix is present on the feature name, it 
refers to a feature defined in the module that was imported with that 
prefix, or the local module if the prefix matches the local module’s 
prefix. Otherwise, a feature with the matching name MUST be defined 
in the current module or an included submodule.

Since submodules cannot include the parent module, any features in 
the module that need to be exposed to submodules MUST be defined in a 
submodule. Submodules can then include this submodule to find the 
definition of the feature.

7.18.3 deviation声明

The “deviation” statement defines a hierarchy of a module that the 
device does not implement faithfully. The argument is a string that 
identifies the node in the schema tree where a deviation from the 
module occurs. This node is called the deviation’s target node. The 
contents of the “deviation” statement give details about the 
deviation.

The argument string is an absolute schema node identifier (see 
Section 6.5).

Deviations define the way a device or class of devices deviate from a 
standard. This means that deviations MUST never be part of a 
published standard, since they are the mechanism for learning how 
implementations vary from the standards.

Device deviations are strongly discouraged and MUST only be used as a 
last resort. Telling the application how a device fails to follow a 
standard is no substitute for implementing the standard correctly. A 
device that deviates from a module is not fully compliant with the 
module.

However, in some cases, a particular device may not have the hardware 
or software ability to support parts of a standard module. When this 
occurs, the device makes a choice either to treat attempts to 
configure unsupported parts of the module as an error that is 
reported back to the unsuspecting application or ignore those 
incoming requests. Neither choice is acceptable.

Instead, YANG allows devices to document portions of a base module 
that are not supported or supported but with different syntax, by 
using the “deviation” statement.

7.18.3.1 deviation的substatements

             +--------------+----------+-------------+
             | substatement | section  | cardinality |
             +--------------+----------+-------------+
             | description  | 7.19.3   | 0..1        |
             | deviate      | 7.18.3.2 | 1..n        |
             | reference    | 7.19.4   | 0..1        |
             +--------------+----------+-------------+
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

7.18.3.2 divate声明

The “deviate” statement defines how the device’s implementation of 
the target node deviates from its original definition. The argument 
is one of the strings “not-supported”, “add”, “replace”, or “delete”.

The argument “not-supported” indicates that the target node is not 
implemented by this device.

The argument “add” adds properties to the target node. The 
properties to add are identified by substatements to the “deviate” 
statement. If a property can only appear once, the property MUST NOT 
exist in the target node.

The argument “replace” replaces properties of the target node. The 
properties to replace are identified by substatements to the 
“deviate” statement. The properties to replace MUST exist in the 
target node.

The argument “delete” deletes properties from the target node. The 
properties to delete are identified by substatements to the “delete” 
statement. The substatement’s keyword MUST match a corresponding 
keyword in the target node, and the argument’s string MUST be equal 
to the corresponding keyword’s argument string in the target node.

                   The deviates's Substatements

             +--------------+---------+-------------+
             | substatement | section | cardinality |
             +--------------+---------+-------------+
             | config       | 7.19.1  | 0..1        |
             | default      | 7.6.4   | 0..1        |
             | mandatory    | 7.6.5   | 0..1        |
             | max-elements | 7.7.4   | 0..1        |
             | min-elements | 7.7.3   | 0..1        |
             | must         | 7.5.3   | 0..n        |
             | type         | 7.4     | 0..1        |
             | unique       | 7.8.3   | 0..n        |
             | units        | 7.3.3   | 0..1        |
             +--------------+---------+-------------+
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

7.18.3.3 使用用例

In this example, the device is informing client applications that it 
does not support the “daytime” service in the style of RFC 867.

 deviation /base:system/base:daytime {
     deviate not-supported;
 }
  • 1
  • 2
  • 3
  • 4

The following example sets a device-specific default value to a leaf 
that does not have a default value defined:

 deviation /base:system/base:user/base:type {
     deviate add {
         default "admin"; // new users are 'admin' by default
     }
 }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

In this example, the device limits the number of name servers to 3:

 deviation /base:system/base:name-server {
     deviate replace {
         max-elements 3;
     }
 }                 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

If the original definition is:

 container system {
     must "daytime or time";
     ...
 }
  • 1
  • 2
  • 3
  • 4
  • 5

a device might remove this must constraint by doing:

 deviation "/base:system" {
     deviate delete {
         must "daytime or time";
     }
 }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

7.19 通用的声明

本小节定义了一些对其他声明来说都可以用的substatements。

7.19.1 config声明

“config”声明有一个参数,取值为“true”或者“false”。如果值为“true”,则表示本定义表示的是configuration。定义configuration的data nodes会是 request的回应的一部分,能够放在或者 request中发送出去。

如果值为“false”,则表示本定义表示的是state data。定义state data的data nodes会是对 request的回应的一部分,单不会回应 request,并且不能放到或者 request中。

如果没有指定“config”,则默认值和其parent schema node的“config”的值一样。如果parent node是一个“case” node,则这个值就和“case”node的parent “choice” noce相同。

如果top node没有指定“config”声明,则默认值为“true”。

如果一个node的“config”设置为“false”,则该节点的所有子节点都不能将“config”设置为“true”。

7.19.2 status声明

“status”声明的参数是一个字符串,是“current”,“deprecated”或者“obsolete”中的一个。

  • “current”意味着该定义在当前是有效的。
  • “deprecated”表示该定义已经被废弃,不过保证在暂时在后续的实现中支持该定义,以保证向前兼容。
  • “obsolete”意味着这个定义已经被废弃,并且 SHOULD NOT 被实现。

如果没有指定status,则默认值为“current”。

如果一个定义是“current”,则它 MUST NOT 在同一个module中引用“deprecated”或“obsolete”定义。

如果一个定义是“deprecated”,则它 MUST NOT 在同一个module中引用“obsolete”定义。

比如说,下面的例子就是非法的:

 typedef my-type {
   status deprecated;
   type int32;
 }

 leaf my-leaf {
   status current;
   type my-type; // illegal, since my-type is deprecated
 }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

7.19.3 description声明

The “description” statement takes as an argument a string that 
contains a human-readable textual description of this definition. 
The text is provided in a language (or languages) chosen by the 
module developer; for the sake of interoperability, it is RECOMMENDED 
to choose a language that is widely understood among the community of 
network administrators who will use the module.

7.19.4 reference声明

“reference”声明有一个参数,是字符串,该参数被用来指定一个到外部文档的交叉引用,既可以是定义了相关管理信息的另一个module,也可以是能对本定义提供相关额外信息的一个文档。

比如,定义了名为“uri” 的一个typedef,可以这么写:

 typedef uri {
   type string;
   reference
     "RFC 3986: Uniform Resource Identifier (URI): Generic Syntax";
   ...
 }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

7.19.5 when声明

“when”声明可以使它的parent data 定义声明变成有条件的。由其parent data定义声明所定义的node仅当该“when”声明提供的要求(condition)得到满足时才有可能是有效的。该声明的参数是一个XPath表达式(见Section 6.4),该表达式被用来精确描述这个条件(condition)。如果XPath表达式针对特定的实例被评估为“true”的话,则该parent data定义声明所定义的node就是有效的,反之亦然。

更多信息可见Section 8.3.2。

The XPath expression is conceptually evaluated in the following 
context, in addition to the definition in Section 6.4.1:

o If the “when” statement is a child of an “augment” statement, then 
the context node is the augment’s target node in the data tree, if 
the target node is a data node. Otherwise, the context node is 
the closest ancestor node to the target node that is also a data 
node.

o If the “when” statement is a child of a “uses”, “choice”, or 
“case” statement, then the context node is the closest ancestor 
node to the “uses”, “choice”, or “case” node that is also a data 
node.

o If the “when” statement is a child of any other data definition 
statement, the context node is the data definition’s node in the 
data tree.

o The accessible tree is made up of all nodes in the data tree, and 
all leafs with default values in use (see Section 7.6.1).

The accessible tree depends on the context node:

o If the context node represents configuration, the tree is the data 
in the NETCONF datastore where the context node exists. The XPath 
root node has all top-level configuration data nodes in all 
modules as children.

o If the context node represents state data, the tree is all state 
data on the device, and the datastore. The XPath root 
node has all top-level data nodes in all modules as children.

o If the context node represents notification content, the tree is 
the notification XML instance document. The XPath root node has 
the element representing the notification being defined as the 
only child.

o If the context node represents RPC input parameters, the tree is 
the RPC XML instance document. The XPath root node has the 
element representing the RPC operation being defined as the only 
child.

o If the context node represents RPC output parameters, the tree is 
the RPC reply instance document. The XPath root node has the 
elements representing the RPC output parameters as children.

The result of the XPath expression is converted to a boolean value 
using the standard XPath rules.

Note that the XPath expression is conceptually evaluated. This means 
that an implementation does not have to use an XPath evaluator on the 
device. The “when” statement can very well be implemented with 
specially written code.

8 constraints

第八章仅仅给出目录,具体内容感觉暂时不需要看。

8.1 constraints on data

8.2. Hierarchy of Constraints

8.3. Constraint Enforcement Model

8.3.1. Payload Parsing

8.3.2. NETCONF Processing

8.3.3. Validation

9 内置类型

这一章暂时没有必要看。稍微对编程语言有点了解,就能把这里的内置类型理解个差不多。遇到问题的时候再回头翻原文吧。

10 更新module

这一章内容比较少,不过又不是自己写module,所以暂时也没必要看。

11 YIN

好像完全没有见过YIN的应用。

一个YANG module能被转换为一种可选的基于XML语法的格式,称为YIN。被转换的module称为YIN module。本小节描述了这YANG和YIN这两种格式之间的映射关系。

YANG和YIN格式使用不同的符号包含了同样的信息。YIN的符号使得开发者能够在XML中表示YANG的data models,因此能够使用基于XML的工具对数据做过滤,验证,代码和文档的自动生成以及其它的工作。想XSLT或XML 验证器这样的工具就能用到了。

YANG和YIN之间的映射不会改变model本身的内容。comments和whitespace不会被保留。

11.1 正规的YIN定义

在YANG的keywords和YIN的elements之间有一对一的双射。一个YIN element的local name等同于对应的yANG的keyword。这意味着,YIN文档中的文档元素(root)总是和YANG中的或对应。

对应到YANG keywords的YIN elements的namespace是“urn:ietf:params:xml:ns:yang:yin:1”。

对应到YANG的extension keywords的YIN elements属于extension关键词通过“extension”声明宣告的YANG module的namespace。

所有的YIN elements的名字 MUST 上述指定的namespaces相匹配,也就是要使用标准的[XML-NAMES]机制,比如:“xmlns”以及“xmlns:xxx”属性。

YANG声明的参数在YIN中是作为XML attribute或者keyword element的subelement而存在。Table 1定义了YANG keywords到YIN的映射关系。对于extensions来说,参数映射是在“extension”声明中指定的(见Section 7.17)。对于参数,有下面的规则:

  • 如果参数被映射为一个attribute,则该attribute没有namespace。
  • 如果参数被映射为一个element,则其namespace和其parent keyword element一样。
  • 如果参数被映射为一个element,则它 MUST 是keyword element的第一个子节点。

YANG声明的substatements会被映射为该声明对应的keyword element的children,substatements之间的相对顺序 MUST和YANG中定义的顺序完全一致。

YANG中的comments MAY 映射为XML的comments。

           Mapping of arguments of the YANG statements.

        +------------------+---------------+-------------+
        | keyword          | argument name | yin-element |
        +------------------+---------------+-------------+
        | anyxml           | name          | false       |
        | argument         | name          | false       |
        | augment          | target-node   | false       |
        | base             | name          | false       |
        | belongs-to       | module        | false       |
        | bit              | name          | false       |
        | case             | name          | false       |
        | choice           | name          | false       |
        | config           | value         | false       |
        | contact          | text          | true        |
        | container        | name          | false       |
        | default          | value         | false       |
        | description      | text          | true        |
        | deviate          | value         | false       |
        | deviation        | target-node   | false       |
        | enum             | name          | false       |
        | error-app-tag    | value         | false       |
        | error-message    | value         | true        |
        | extension        | name          | false       |
        | feature          | name          | false       |
        | fraction-digits  | value         | false       |
        | grouping         | name          | false       |
        | identity         | name          | false       |
        | if-feature       | name          | false       |
        | import           | module        | false       |
        | include          | module        | false       |
        | input            | <no argument> | n/a         |
        | key              | value         | false       |
        | leaf             | name          | false       |
        | leaf-list        | name          | false       |
        | length           | value         | false       |
        | list             | name          | false       |
        | mandatory        | value         | false       |
        | max-elements     | value         | false       |
        | min-elements     | value         | false       |
        | module           | name          | false       |
        | must             | condition     | false       |
        | namespace        | uri           | false       |
        | notification     | name          | false       |
        | ordered-by       | value         | false       |
        | organization     | text          | true        |
        | output           | <no argument> | n/a         |
        | path             | value         | false       |
        | pattern          | value         | false       |
        | position         | value         | false       |
        | prefix           | value         | false       |
        | presence         | value         | false       |
        | range            | value         | false       |
        | reference        | text          | true        |
        | refine           | target-node   | false       |
        | require-instance | value         | false       |
        | revision         | date          | false       |
        | revision-date    | date          | false       |
        | rpc              | name          | false       |
        | status           | value         | false       |
        | submodule        | name          | false       |
        | type             | name          | false       |
        | typedef          | name          | false       |
        | unique           | tag           | false       |
        | units            | name          | false       |
        | uses             | name          | false       |
        | value            | value         | false       |
        | when             | condition     | false       |
        | yang-version     | value         | false       |
        | yin-element      | value         | false       |
        +------------------+---------------+-------------+

                              Table 1
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74

11.1.1 使用用例

下面的YANG module:

 module acme-foo {
     namespace "http://acme.example.com/foo";
     prefix "acfoo";

     import my-extensions {
         prefix "myext";
     }

     list interface {
         key "name";
         leaf name {
             type string;
         }

         leaf mtu {
             type uint32;
             description "The MTU of the interface.";
             myext:c-define "MY_MTU";
         }
     }
 }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22

其中的“c-define”定义在Section 7.7.3,将上述module转化为下面的YIN:

     <module name="acme-foo"
             xmlns="urn:ietf:params:xml:ns:yang:yin:1"
             xmlns:acfoo="http://acme.example.com/foo"
             xmlns:myext="http://example.com/my-extensions">

       <namespace uri="http://acme.example.com/foo"/>
       <prefix value="acfoo"/>

       <import module="my-extensions">
         <prefix value="myext"/>
       </import>

       <list name="interface">
         <key value="name"/>
         <leaf name="name">
           <type name="string"/>
         </leaf>
         <leaf name="mtu">
           <type name="uint32"/>
           <description>
             <text>The MTU of the interface.</text>
           </description>
           <myext:c-define name="MY_MTU"/>
         </leaf>
       </list>
     </module>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26

12 YANG ABNF Grammar

ABNF, Augmented Backus-Naur Form

这一章看不懂,后面就不粘了。

在YANG中,几乎所有的statements都是无序的。ABNF grammar 【RFC5234】 为这些声明定义了标准的顺序。为了提高module的可读性, RECOMMENDED 有序。

13 YANG相关错误的Error Responses

这一章对于我们实现来说,并不关心,所以跳过。

14 IANA Considerations

这一章同样没什么用。

This document defines a registry for YANG module and submodule names. 
The name of the registry is “YANG Module Names”.

The registry shall record for each entry:

o the name of the module or submodule

o for modules, the assigned XML namespace

o for modules, the prefix of the module

o for submodules, the name of the module it belongs to

o a reference to the (sub)module’s documentation (e.g., the RFC 
number)

There are no initial assignments.

For allocation, RFC publication is required as per RFC 5226 
[RFC5226]. All registered YANG module names MUST comply with the 
rules for identifiers stated in Section 6.2, and MUST have a module 
name prefix.

The module name prefix ‘ietf-’ is reserved for IETF stream documents 
[RFC4844], while the module name prefix ‘irtf-’ is reserved for IRTF 
stream documents. Modules published in other RFC streams MUST have a 
similar suitable prefix.

All module and submodule names in the registry MUST be unique.

All XML namespaces in the registry MUST be unique.

This document registers two URIs for the YANG and YIN XML namespaces 
in the IETF XML registry [RFC3688]. Following the format in RFC 
3688, the following have been registered.

 URI: urn:ietf:params:xml:ns:yang:yin:1

 URI: urn:ietf:params:xml:ns:yang:1

 Registrant Contact: The IESG.

 XML: N/A, the requested URIs are XML namespaces.
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

This document registers two new media types as defined in the 
following sections.

14.1 Media type application/yang

MIME media type name: application

MIME subtype name: yang

Mandatory parameters: none

Optional parameters: none

Encoding considerations: 8-bit

Security considerations: See Section 15 in RFC 6020

Interoperability considerations: None

Published specification: RFC 6020

Applications that use this media type:

YANG module validators, web servers used for downloading YANG
modules, email clients, etc.
  • 1
  • 2
  • 3

Additional information:

 Magic Number:  None

 File Extension:  .yang

 Macintosh file type code:  'TEXT'
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

Personal and email address for further information: 
Martin Bjorklund mbj@tail-f.com

Intended usage: COMMON

Author: 
This specification is a work item of the IETF NETMOD working group, 
with mailing list address netmod@ietf.org
Change controller: 
The IESG iesg@ietf.org

14.2 Media type application/yin+xml

MIME media type name: application

MIME subtype name: yin+xml

Mandatory parameters: none

Optional parameters:

 "charset":  This parameter has identical semantics to the charset
 parameter of the "application/xml" media type as specified in
 [RFC3023].
  • 1
  • 2
  • 3
  • 4

Encoding considerations:

 Identical to those of "application/xml" as
 described in [RFC3023], Section 3.2.
  • 1
  • 2
  • 3

Security considerations: See Section 15 in RFC 6020

Interoperability considerations: None

Published specification: RFC 6020

Applications that use this media type:

YANG module validators, web servers used for downloading YANG
modules, email clients, etc.
  • 1
  • 2
  • 3

Additional information:

 Magic Number:  As specified for "application/xml" in [RFC3023],
                Section 3.2.

 File Extension:  .yin

 Macintosh file type code:  'TEXT'
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

Personal and email address for further information: 
Martin Bjorklund mbj@tail-f.com

Intended usage: COMMON

Author: 
This specification is a work item of the IETF NETMOD working group, 
with mailing list address netmod@ietf.org.

Change controller: 
The IESG iesg@ietf.org

15 Security Considerations

This document defines a language with which to write and read 
descriptions of management information. The language itself has no 
security impact on the Internet.

The same considerations are relevant as for the base NETCONF protocol 
(see [RFC4741], Section 9).

Data modeled in YANG might contain sensitive information. RPCs or 
notifications defined in YANG might transfer sensitive information.

Security issues are related to the usage of data modeled in YANG. 
Such issues shall be dealt with in documents describing the data 
models and documents about the interfaces used to manipulate the data 
e.g., the NETCONF documents.

Data modeled in YANG is dependent upon:

o the security of the transmission infrastructure used to send 
sensitive information.

o the security of applications that store or release such sensitive 
information.

o adequate authentication and access control mechanisms to restrict 
the usage of sensitive data.

YANG parsers need to be robust with respect to malformed documents. 
Reading malformed documents from unknown or untrusted sources could 
result in an attacker gaining privileges of the user running the YANG 
parser. In an extreme situation, the entire machine could be 
compromised.

16 贡献者

The following people all contributed significantly to the initial 
YANG document:

- Andy Bierman (Brocade)
- Balazs Lengyel (Ericsson)
- David Partain (Ericsson)
- Juergen Schoenwaelder (Jacobs University Bremen)
- Phil Shafer (Juniper Networks)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

17 Acknowledgements

The editor wishes to thank the following individuals, who all 
provided helpful comments on various versions of this document: 
Mehmet Ersue, Washam Fan, Joel Halpern, Leif Johansson, Ladislav 
Lhotka, Gerhard Muenz, Tom Petch, Randy Presuhn, David Reid, and Bert 
Wijnen.

18 引用

18.1 对标准的引用

[ISO.10646]  International Organization for Standardization,
            "Information Technology - Universal Multiple-Octet Coded
            Character Set (UCS)", ISO Standard 10646:2003, 2003.

[RFC2119]    Bradner, S., "Key words for use in RFCs to Indicate
            Requirement Levels", BCP 14, RFC 2119, March 1997.

[RFC3023]    Murata, M., St. Laurent, S., and D. Kohn, "XML Media
            Types", RFC 3023, January 2001.

[RFC3629]    Yergeau, F., "UTF-8, a transformation format of ISO
            10646", STD 63, RFC 3629, November 2003.

[RFC3688]    Mealling, M., "The IETF XML Registry", BCP 81, RFC 3688,
            January 2004.

[RFC3986]    Berners-Lee, T., Fielding, R., and L. Masinter, "Uniform
            Resource Identifier (URI): Generic Syntax", STD 66,
            RFC 3986, January 2005.

[RFC4648]    Josefsson, S., "The Base16, Base32, and Base64 Data
            Encodings", RFC 4648, October 2006.

[RFC4741]    Enns, R., "NETCONF Configuration Protocol", RFC 4741,
            December 2006.

[RFC5226]    Narten, T. and H. Alvestrand, "Guidelines for Writing an
            IANA Considerations Section in RFCs", BCP 26, RFC 5226,
            May 2008.

[RFC5234]    Crocker, D. and P. Overell, "Augmented BNF for Syntax
            Specifications: ABNF", STD 68, RFC 5234, January 2008.

[RFC5277]    Chisholm, S. and H. Trevino, "NETCONF Event
            Notifications", RFC 5277, July 2008.

[XML-NAMES]  Hollander, D., Tobin, R., Thompson, H., Bray, T., and A.
            Layman, "Namespaces in XML 1.0 (Third Edition)", World
            Wide Web Consortium Recommendation REC-xml-names-
            20091208, December 2009,
            <http://www.w3.org/TR/2009/REC-xml-names-20091208>.

[XPATH]      Clark, J. and S. DeRose, "XML Path Language (XPath)
            Version 1.0", World Wide Web Consortium
            Recommendation REC-xpath-19991116, November 1999,
            <http://www.w3.org/TR/1999/REC-xpath-19991116>.

[XSD-TYPES]  Malhotra, A. and P. Biron, "XML Schema Part 2: Datatypes
            Second Edition", World Wide Web Consortium
            Recommendation REC-xmlschema-2-20041028, October 2004,
            <http://www.w3.org/TR/2004/REC-xmlschema-2-20041028>.                           
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52

18.2 对informative文稿的引用

[RFC2578]    McCloghrie, K., Ed., Perkins, D., Ed., and J.
            Schoenwaelder, Ed., "Structure of Management Information
            Version 2 (SMIv2)", STD 58, RFC 2578, April 1999.

[RFC2579]    McCloghrie, K., Ed., Perkins, D., Ed., and J.
            Schoenwaelder, Ed., "Textual Conventions for SMIv2",
            STD 58, RFC 2579, April 1999.

[RFC3780]    Strauss, F. and J. Schoenwaelder, "SMIng - Next
            Generation Structure of Management Information",
            RFC 3780, May 2004.

[RFC4844]    Daigle, L. and Internet Architecture Board, "The RFC
            Series and RFC Editor", RFC 4844, July 2007.

[XPATH2.0]   Berglund, A., Boag, S., Chamberlin, D., Fernandez, M.,
            Kay, M., Robie, J., and J. Simeon, "XML Path Language
            (XPath) 2.0", World Wide Web Consortium
            Recommendation REC-xpath20-20070123, January 2007,
            <http://www.w3.org/TR/2007/REC-xpath20-20070123>.                
[XSLT]       Clark, J., "XSL Transformations (XSLT) Version 1.0",
            World Wide Web Consortium Recommendation REC-xslt-
            19991116, November 1999,
            <http://www.w3.org/TR/1999/REC-xslt-19991116>.
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25

作者联系地址

Martin Bjorklund (editor) 
Tail-f Systems

EMail: mbj@tail-f.com

 

 

转载自:https://blog.csdn.net/ohohoohoho/article/details/52129076

相关链接:https://blog.csdn.net/qiuluzhi/article/details/79347573

  • 1
    点赞
  • 0
    评论
  • 6
    收藏
  • 一键三连
    一键三连
  • 扫一扫,分享海报

©️2021 CSDN 皮肤主题: 技术黑板 设计师:CSDN官方博客 返回首页
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值