YANG语法

来源:互联网 发布:淘宝精简版永不升级 编辑:程序博客网 时间:2024/06/07 06:44





Yang语言.html




简介

YANG其实是一种数据建模语言,专门为netconf定制的一种模型配置语言,
NETCONF协议采用XML(可扩展标记语言)作为配置数据和协议消息的编码方式,用C/S和RPC方式来获取,更新或删除设备中的相应的部分或所有管理信息.
XML可以表达复杂的、具有内在逻辑关系的模型化的管理对象,大大提高了操作效率和对象标准化.XSD,Xpath, SOAP,XSLT等XML技术都可以应用到NETCONF协议中。
另外,协议采用SSHv2,SOAP,BEEP等传输方式,来提高传输的可靠性、安全性和交互性。
netconf的四层结构:

`    +-------------+ +-----------------------------+ 
(4) | Content | | Configuration data |
+-------------+ +-----------------------------+
| |
+-------------+ +-----------------------------+
(3) | Operations | | <get-config>, <edit-config> |
+-------------+ +-----------------------------+
| |
+-------------+ +-----------------------------+
(2) | RPC | | <rpc>, <rpc-reply> |
+-------------+ +-----------------------------+
| |
+-------------+ +-----------------------------+
(1) | Transport | | BEEP, SSH, SSL, console |
| Protocol | | |
+-------------+ +-----------------------------+
“> +————-+ +—————————–+
(4) | Content | | Configuration data |
+————-+ +—————————–+
| |
+————-+ +—————————–+
(3) | Operations | | <get-config>, <edit-config> |
+————-+ +—————————–+
| |
+————-+ +—————————–+
(2) | RPC | | <rpc>, <rpc-reply> |
+————-+ +—————————–+
| |
+————-+ +—————————–+
(1) | Transport | | BEEP, SSH, SSL, console |
| Protocol | | |
+————-+ +—————————–+

YANG用来配置模型以及通过网络配置协议(NETCONF)、NETCONF远程调用和NETCONF通知来声明数据。YANG用来模拟业务操作和NETCONF的内容层。
官方的文档是:rfc6020_with_content,可以在网上下载看。

下面介绍一个yang语言的语法:
yang模型是用来表示配置模型的,有下面这些关键字:

1 module

一个module的定义包含几个部分:
第一部分是 namespace(命名空间),prefix(缩略语), import(引入的其他模块),include(包含哪些子模块submodule),
第二部分是这个module的历史信息以及相关描述,organization,contact,description,revision;其中organization,contact,description,revision这些可以不写,也可以编译通过。一般项目会要求写上revision修改记录。
第三部分是当前这个module里面的数据形式定义。
如:

   module Equipment { 
namespace "urn:com:params:xml:ns:yang:ran:Equipment";
prefix Equipment;

  import ManagedElement{    prefix ME;  }//revision这里没写。  augment &quot;/ME:ManagedElement&quot;{    container Equipment {        leaf name{        type string;    }  ......  }

}
”> module Equipment {
namespace “urn:com:params:xml:ns:yang:ran:Equipment”;
prefix Equipment;

  import ManagedElement{    prefix ME;  }//revision这里没写。  augment "/ME:ManagedElement"{    container Equipment {        leaf name{        type string;    }  ......  }

}

一个Module下面可以定义什么类型,我们可以查看协议rfc6020_with_content.pdf,如下这种:
7.1.1节定义的

`                +--------------+---------+-------------+ 
| 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 |
+--------------+---------+-------------+
“> +————–+———+————-+
| 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 |
+————–+———+————-+

意思就是说module下面支持从anyxml到yang-version这些关键字的定义。下面介绍各种关键字的时候不在重述这一部分。详细可查协议。

2 submodule

submodule是子模块的意思。submodule不用写module的第一部分,但是需要指定它的归属,如下

`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...
}
“>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…
}

并且一定要注意的是submodule归属于哪一个module,一定要在这个module里面用include包含这个submodule.
上面这个例子中,它是归属于acme-system,那么在acme-system里面必须要有这么一个引用:

module acme-system { 
namespace "urn:com:params:xml:ns:yang:ran:acme-system";
prefix acme;

include acme-types {}
......
}

“>module acme-system {
namespace “urn:com:params:xml:ns:yang:ran:acme-system”;
prefix acme;

include acme-types {}
……
}

3 leaf

最末端的叶子节点,它下面不包含任何节点或者一组节点,叶子节点里面就是类型定义、默认值、取值范围、是否是必填、是否是不可配等

leaf支持的定义

`+--------------+---------+-------------+ 
| 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 |
+--------------+---------+-------------+
“>+————–+———+————-+
| 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 |
+————–+———+————-+

下面举个例子:

`   leaf Param { 
type string {
length "0..34";
}
mandatory true;//必须配置的
default 0;
units s;//单位
description "Param";
}
“> leaf Param {
type string {
length “0..34”;
}
mandatory true;//必须配置的
default 0;
units s;//单位
description “Param”;
}

上面是字符类型的

`leaf Param { 
type int32 {
length "0..65535";
}
default 0;
description "Param";
}
“>leaf Param {
type int32 {
length “0..65535”;
}
default 0;
description “Param”;
}

上面是数值类型的,其中int4的范围是-16到15,int8的范围是-256到255,以此类推。
int是无符号的,uint是指正整型,uint4的范围是0..16,以此类推。

`leaf holdoverSwitch { 
type enumeration {
enum Disable;
enum Enable;
}
default Enable;
description "Holdover Time-Out Switch";
}
“>leaf holdoverSwitch {
type enumeration {
enum Disable;
enum Enable;
}
default Enable;
description “Holdover Time-Out Switch”;
}

这种是枚举类型的,其中枚举类型表示的时候都是显示值,其中内存值如果没有特别注明就是从0开始,如果我们的枚举不是从0开始顺序枚举的,需要另外加上value值,如下

`leaf radioMode { 
type enumeration {
enum LTE-FDD { value 16; }
enum LTE-TDD { value 32; }
}
default LTE-TDD;
description "Cell type";
}
“>leaf radioMode {
type enumeration {
enum LTE-FDD { value 16; }
enum LTE-TDD { value 32; }
}
default LTE-TDD;
description “Cell type”;
}

另外枚举类型需要注意:enum后面的这个显示的字符串,不支持中文,并且如果字符串中间有空格,需要用引号引起来,比如:

`type enumeration { 
enum "LTE FDD" { value 16; }
enum "LTE TDD" { value 32; }
}
“>type enumeration {
enum “LTE FDD” { value 16; }
enum “LTE TDD” { value 32; }
}

leaf解析成xml的时候是作为一个元素来解析的
比如上面的最后一个例子对应的xml数据就是

`&lt;radioMode&gt;16&lt;/radioMode&gt; 
“><radioMode>16</radioMode>

leaf下面还有union和choice.
leaf的默认值的处理要特别注意:如果用get-config操作获取数据的时候,如果当前叶子节点没有数据,但是存在默认值,系统会把默认值返回。这和之前的网管是不一样的。

reference是使用一个字符串定义引用外部文件的连接,或提供与此相关的附加信息的文档定义;
config是定义该节点是否可配,默认是可配的,如果要定义成不可配,需要加上config false;
union是说如果节点定义是union的,表示这个节点的类型是它下面的类型中的一个,这里有个例子:

`typedef ip-address { 
type union {
type ipv4-address;
type ipv6-address;
}
description
"The ip-address type represents an IP address and is IP version neutral.";
reference
"RFC 4007: IPv6 Scoped Address Architecture";
}
“>typedef ip-address {
type union {
type ipv4-address;
type ipv6-address;
}
description
“The ip-address type represents an IP address and is IP version neutral.”;
reference
“RFC 4007: IPv6 Scoped Address Architecture”;
}

if-feature是和feature结合使用的,是说有些特征有条件的存在于模型上。yang模型支持设备提供不同的能力和角色。
举个协议上的例子:

`module syslog { 
...
feature local-storage {
description
"This feature means the device supports local storage 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.";
}
}
}
“>module syslog {

feature local-storage {
description
“This feature means the device supports local storage 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.”;
}
}
}

意思就是说local-storage这个特征,是在下面有if-feature指向了这个feature的时候才会生效。如果module里面没有if-feature local-storage,那么local-storage这个特征将不会被使用。

must是用来写简单约束的。
must在一些关键字下面的不支持的,用之前要看一下协议

`      leaf intraA3Hysteresis4Cate0 { 
type decimal64 {
fraction-digits 1;
range "0..15";
}
default 1.5;
units dB;
description "This parameter indicates the hysteresis used for judging event during handover.";
}
must " intraA3Hysteresis4Cate0*10 mod 5 = 0 " {
error-message "intraA3Hysteresis4Cate0 must be in [0..15] step 0.5";
}
“> leaf intraA3Hysteresis4Cate0 {
type decimal64 {
fraction-digits 1;
range “0..15”;
}
default 1.5;
units dB;
description “This parameter indicates the hysteresis used for judging event during handover.”;
}
must ” intraA3Hysteresis4Cate0*10 mod 5 = 0 ” {
error-message “intraA3Hysteresis4Cate0 must be in [0..15] step 0.5”;
}

这个例子就是定义步长的。
还有类似这种的:

`leaf interCarriFreq { 
type decimal64 {
fraction-digits 1;
range "0..6000";
}
mandatory true;
units MHz;
description "This parameter is used to configure the frequency of intra-LTE inter-frequency.";
}
must "freqBandInd != 1 or " +
"(freqBandInd = 1 and interCarriFreq &gt;= 2110 and interCarriFreq &lt;=2170)" {
error-message "freqBandInd=1, interCarriFreq must be [2110..2170]";
}
“>leaf interCarriFreq {
type decimal64 {
fraction-digits 1;
range “0..6000”;
}
mandatory true;
units MHz;
description “This parameter is used to configure the frequency of intra-LTE inter-frequency.”;
}
must “freqBandInd != 1 or ” +
“(freqBandInd = 1 and interCarriFreq >= 2110 and interCarriFreq <=2170)” {
error-message “freqBandInd=1, interCarriFreq must be [2110..2170]”;
}

must 后面有引号引起来的就是条件部分,然后是大括号,里面是如果不符合约束,那么错误信息的定义。

mandatory这个关键字是定义该节点是否必须配置,默认是false。如果定义成mandatory true,那么就不能用default。这点需要注意。
我理解这里的意思是如果这个节点必须配置,那么默认值就会被忽略。并且在模式树上,这个节点是一定存在的。
when的用法在另一篇文档中有说明。
别的类型在这里不详细说明。

4 leaf-list

表示数组的意思,但是和我们理解的数组不太一样,有一个很明显不同,yang定义的这个数组当中不允许每个元素的值相同。
例子:

`leaf-list blackListIP { 
max-elements 20;
type mocommon:ip-address;
description "IP Blacklist";
}
“>leaf-list blackListIP {
max-elements 20;
type mocommon:ip-address;
description “IP Blacklist”;
}

这个里面max-elements是指这个数组的最大元素数,如果需要定义这个数组是必须配置的,那么需要在定义一个:

`min-elements 1; 
“>min-elements 1;

意思就是这个数组最低要配置一个元素。
leaf-list支持下面这些

`+--------------+---------+-------------+ 
| 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 |
+--------------+---------+-------------+
“>+————–+———+————-+
| 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 |
+————–+———+————-+

常用的上面已经讲过,这里特别说一下ordered-by。这个是排序的意思。如果不定义,那么netconf将采用默认的方式进行排序,但这里也提供给用户定义,可以指定有系统排序还是用户排序。假设当前这个数组排序有特别的意思,那么用户可以指定排序方式。
协议中有例子,谁有兴趣可以详细研究一下

5 list

list表示一组节点的集合。
list下面包含这些关键字:

`+--------------+---------+-------------+ 
| 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 |
+--------------+---------+-------------+
“>+————–+———+————-+
| 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 |
+————–+———+————-+

例子:

`list VMDevice { 
key serialInfo;
leaf serialInfo {
type string;
}
leaf name {
type string;
}
}
“>list VMDevice {
key serialInfo;
leaf serialInfo {
type string;
}
leaf name {
type string;
}
}

一个list中必须存在主键值,即必须定义Key。
这个其实可以理解,因为yang当中的所有数组,它都认为数组内部的元素是唯一的,不允许相同的情况存在。
数据是这么构建的:这个list的上级节点在这里不进行描述了

`&lt;VMDevice&gt; 
&lt;serialInfo&gt;1&lt;/serialInfo&gt;
&lt;name&gt;device1&lt;/name&gt;
&lt;/VMDevice&gt;
&lt;VMDevice&gt;
&lt;serialInfo&gt;2&lt;/serialInfo&gt;
&lt;name&gt;device2&lt;/name&gt;
&lt;/VMDevice&gt;
...
“><VMDevice>
<serialInfo>1</serialInfo>
<name>device1</name>
</VMDevice>
<VMDevice>
<serialInfo>2</serialInfo>
<name>device2</name>
</VMDevice>

其中需要注意的是,这个list的主键是serialInfo,那么如果数据当中serialInfo这个的值有相同的情况,那么yang模型会不认,要不然是报错处理,要不然就是覆盖处理。

6 container

container是单例。

container ManagedElement { 
leaf ManagedElementId {
type int32;
mandatory true;
}
leaf meId {    type    int32;    mandatory true;}leaf locationName {    type string;    mandatory true;}

}

”>container ManagedElement {
leaf ManagedElementId {
type int32;
mandatory true;
}
leaf meId {    type    int32;    mandatory true;}leaf locationName {    type string;    mandatory true;}

}

container和list是可以直接挂在配置模型树上的。
container有两个模式,一个是默认值模式,一个是presence模式。像上面的例子就是默认值模式,也就是说container的默认情况就是这种。这种节点挂在配置树上之后,如果我们用get-config命令进行获取的时候,如果这个container没有配置数据,那么系统会返回给客户端所有的默认值。——这点和我们以前配置的理解是不一样的
如果我们配置的有数据,那么可以将配置的数据和默认值一并返回。

那么presence定义的情况是怎么样的呢?如果是presence container,并且用户并没有配置这个数据,那么从客户端发命令get-config的时候,并不会返回任何值;如果用户有配置数据,那么再执行命令get-config的时候,系统会返回用户配置的数据以及没有配但是有默认值的数据。
详细的测试过程可以见另外一个文档《prenese关键字的分析》。

上面这个例子的数据格式是:

`&lt;ManagedElement&gt; 
&lt;ManagedElementId&gt;1&lt;/ManagedElementId&gt;
&lt;meId&gt;1&lt;/meId&gt;
&lt;locationName&gt;&lt;/locationName&gt;
&lt;/ManagedElement&gt;
“><ManagedElement>
<ManagedElementId>1</ManagedElementId>
<meId>1</meId>
<locationName></locationName>
</ManagedElement>

当然这个数据只能是一条。

7 typedef
这个就是自定义类型。
yang模型有一些常用的类型,比如int,string,enumation,decimal64(浮点类型)等,如果一个定义在多处都用到了,那么我们不用写很多次,定义成一个类型,引用它就行了

typedef time { 
type string {
length "1..20";
pattern '\d{1,2}:\d{1,2}';
}
}

list SonPolicyAnrTDD {
description "SON ANR Policy";
max-elements 64;
key "sonPolicyId";

    leaf anrAppointRptStartTime {        type time;        default 00:00;        description &quot;&quot;;    }

}

”>typedef time {
type string {
length “1..20”;
pattern ‘\d{1,2}:\d{1,2}’;
}
}

list SonPolicyAnrTDD {
description “SON ANR Policy”;
max-elements 64;
key “sonPolicyId”;

    leaf anrAppointRptStartTime {        type time;        default 00:00;        description "";    }

}

也可以引用别的文件模型里面的type,只用引用这个module就可以用了

module EUtranCellTDD { 
namespace "urn:com:params:xml:ns:yang:ran:4g:eutrancelltdd";
prefix "eutrancelltdd";
import MoCommon {    prefix &quot;mocommon&quot;;}list EUtranCellTDD {        description &quot;E-UTRAN TDD Cell&quot;;        max-elements 36;        key &quot;cellLocalId&quot;;        leaf EUtranCellTDDId {            type mocommon:Mo_Id;            mandatory true;        }}

}

”>module EUtranCellTDD {
namespace “urn:com:params:xml:ns:yang:ran:4g:eutrancelltdd”;
prefix “eutrancelltdd”;
import MoCommon {    prefix "mocommon";}list EUtranCellTDD {        description "E-UTRAN TDD Cell";        max-elements 36;        key "cellLocalId";        leaf EUtranCellTDDId {            type mocommon:Mo_Id;            mandatory true;        }}

}

8 grouping

grouping就是用来定义重复用的一组节点。
可以在一个module里面用,也可以引用别的module里面的grouping
grouping不是一个数据定义状态。不能在配置树上呈现。

module SonCommon { 
namespace "urn:com:params:xml:ns:yang:ran:4g:soncommon";
prefix "soncommon";
grouping son-policy {    leaf sonFuncId {        type int32 {            range &quot;0..255&quot;;        }        default 43;        description &quot;Service Type&quot;;    }    leaf reportSwitch {        type enumeration {            enum Close;            enum Open;        }        default Close;        description &quot;Monitor Message Report Switch&quot;;    }}

}

module SonPolicyPciTDD {
namespace "urn:com:params:xml:ns:yang:ran:4g:sonpolicypcitdd";
prefix "sonpolicypcitdd";

import MoCommon {    prefix &quot;mocommon&quot;;  }import SonCommon {    prefix &quot;soncommon&quot;;}list SonPolicyPciTDD {        description &quot;SON PCI Policy&quot;;        key &quot;sonPolicyId&quot;;        leaf SonPolicyPciTDDId {            type mocommon:Mo_Id;        }        leaf description {            type mocommon:Mo_description;        }        leaf sonPolicyId {            type int32 {                range &quot;47000..47999&quot;;            }            //default 47000;            description                &quot;Policy ID&quot;;        }        uses soncommon:son-policy {            refine sonFuncId {                default 47;            }        } }

}

”>module SonCommon {
namespace “urn:com:params:xml:ns:yang:ran:4g:soncommon”;
prefix “soncommon”;
grouping son-policy {    leaf sonFuncId {        type int32 {            range "0..255";        }        default 43;        description "Service Type";    }    leaf reportSwitch {        type enumeration {            enum Close;            enum Open;        }        default Close;        description "Monitor Message Report Switch";    }}

}

module SonPolicyPciTDD {
namespace “urn:com:params:xml:ns:yang:ran:4g:sonpolicypcitdd”;
prefix “sonpolicypcitdd”;

import MoCommon {    prefix "mocommon";  }import SonCommon {    prefix "soncommon";}list SonPolicyPciTDD {        description "SON PCI Policy";        key "sonPolicyId";        leaf SonPolicyPciTDDId {            type mocommon:Mo_Id;        }        leaf description {            type mocommon:Mo_description;        }        leaf sonPolicyId {            type int32 {                range "47000..47999";            }            //default 47000;            description                "Policy ID";        }        uses soncommon:son-policy {            refine sonFuncId {                default 47;            }        } }

}

如果要用的grouping和之前定义的完全一样,像上述例子,那么直接这样用就行了:
uses soncommon:son-policy;
但是如果要用的grouping和之前定义过的有一些不同,我们也可以用,不过在差异部分重新定义一下就可以了,像上面的例子 refine一样,是默认值不一样,那么重新覆盖上一个就行了。

9 augment

augment是定义往配置树上额外挂载节点,也可表示父子归属关系。

module ENBFunctionTDD { 
namespace "urn:com:params:xml:ns:yang:ran:4g:enbfunctiontdd";
prefix "enbfunctiontdd";
import MoCommon {    prefix &quot;mocommon&quot;;}import ManagedElement {    prefix &quot;ME&quot;;}import Equipment {    prefix &quot;Equipment&quot;;}augment &quot;/ME:ManagedElement&quot; {    container ENBFunctionTDD {        presence  ENBFunctionTDD;        leaf ENBFunctionTDDId {          type uint32 {                range &quot;0..1048575&quot;;            }            mandatory true;            description &quot;RDN&quot;;        }  }

}

”>module ENBFunctionTDD {
namespace “urn:com:params:xml:ns:yang:ran:4g:enbfunctiontdd”;
prefix “enbfunctiontdd”;
import MoCommon {    prefix "mocommon";}import ManagedElement {    prefix "ME";}import Equipment {    prefix "Equipment";}augment "/ME:ManagedElement" {    container ENBFunctionTDD {        presence  ENBFunctionTDD;        leaf ENBFunctionTDDId {          type uint32 {                range "0..1048575";            }            mandatory true;            description "RDN";        }  }

}

这个例子是说ENBFunctionTDD这个节点是挂载在ManagedElement下的,相当于ManagedElement的孩子。
像这种的数据是下面这样的:

`&lt;ManagedElement xmlns="urn:com:params:xml:ns:yang:ran:ManagedElement"&gt; 
&lt;locationName&gt;2&lt;/locationName&gt;
&lt;Id&gt;1&lt;/Id&gt;
&lt;ENBFunctionTDD xmlns="urn:com:params:xml:ns:yang:ran:ENBFunctionTDD"&gt;
&lt;EUtranCellTDD xmlns="urn:com:params:xml:ns:yang:ran:ENBFunctionTDD"&gt;
&lt;mcc&gt;3&lt;/mcc&gt;
&lt;/EUtranCellTDD&gt;
&lt;/ENBFunctionTDD&gt;
&lt;/ManagedElement&gt;
“><ManagedElement xmlns=”urn:com:params:xml:ns:yang:ran:ManagedElement”>
<locationName>2</locationName>
<Id>1</Id>
<ENBFunctionTDD xmlns=”urn:com:params:xml:ns:yang:ran:ENBFunctionTDD”>
<EUtranCellTDD xmlns=”urn:com:params:xml:ns:yang:ran:ENBFunctionTDD”>
<mcc>3</mcc>
</EUtranCellTDD>
</ENBFunctionTDD>
</ManagedElement>

每个module都需要填写上namespace
augment挂载的container,不允许这个container下面的节点定义成mandatory.
但是如果augment挂载的container定义成了prenese,那么下面的节点可以定义成mandatory.

10 rpc

协议中一个很典型的例子:

`rpc activate-software-image { 
input {
leaf image-name {
type string;
}
}
output {
leaf status {
type string;
}
}
}
“>rpc activate-software-image {
input {
leaf image-name {
type string;
}
}
output {
leaf status {
type string;
}
}
}

对应的xml就是:

`&lt;rpc message-id="101" 
xmlns="urn:ietf:params:xml:ns:netconf:base:1.0"&gt;
&lt;activate-software-image xmlns="http://acme.example.com/system"&gt;
&lt;image-name&gt;acmefw-2.3&lt;/image-name&gt;
&lt;/activate-software-image&gt;
&lt;/rpc&gt;
&lt;rpc-reply message-id="101"
xmlns="urn:ietf:params:xml:ns:netconf:base:1.0"&gt;
&lt;status xmlns="http://acme.example.com/system"&gt;
The image acmefw-2.3 is being installed.
&lt;/status&gt;
&lt;/rpc-reply&gt;
“><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>

特别注意,写数据的时候,这一行的定义必不可少。下面才是rpc本身的信息

11 notification

notification就是通知消息,
协议上一个例子是:

`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;
}
}
“>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;
}
}

对应上报的xml就是这样的:

`&lt;notification xmlns="urn:ietf:params:netconf:capability:notification:1.0"&gt; 
&lt;eventTime&gt;2007-09-01T10:00:00Z&lt;/eventTime&gt;
&lt;link-failure xmlns="http://acme.example.com/system"&gt;
&lt;if-name&gt;so-1/2/3.0&lt;/if-name&gt;
&lt;if-admin-status&gt;up&lt;/if-admin-status&gt;
&lt;if-oper-status&gt;down&lt;/if-oper-status&gt;
&lt;/link-failure&gt;
&lt;/notification&gt;
“><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>

同样的这一行必不可少。

12 yang中的path

特别说明一下:在我们mo模型里面,有很多引用字段,那么yang语法中怎么表示呢?
yang语法也是支持的,见下面:

`leaf refSignalResCfgTDD { 
type leafref {
path "/ME:ManagedElement/enbfunctiontdd:ENBFunctionTDD/signalrescfgtdd:SignalResCfgTDD/signalrescfgtdd:sigResIdx";
}
description "";
}
“>leaf refSignalResCfgTDD {
type leafref {
path “/ME:ManagedElement/enbfunctiontdd:ENBFunctionTDD/signalrescfgtdd:SignalResCfgTDD/signalrescfgtdd:sigResIdx”;
}
description “”;
}

上面这个path的意思就是说refSignalResCfgTDD指向的是ManagedElement-ENBFunctionTDD-signalrescfgtdd-sigResIdx的值。
有一点和现在网管不同的是,yang模型必须指向一个叶子节点,并且存储的也是这个节点的值,而不会把路径都记录下来,类似MOI一样。