原文连接:https://www.jianshu.com/p/ca7f5fe11fae
在研究netconf的时候,YANG(RFC6020)是必定绕不过的。花了一些时间看RFC6020,有一点初步的理解,记录下来方便后面查看。node
1 为何要有YANG
netconf须要对设备的配置(configuration)和状态(state)作操做,例如编辑配置,获取状态,所以须要一种语言来对configuration和state进行建模,甚至连“操做”也能够经过YANG来建模。建好的模型,最后以XML的形式进行实例化。打个比方,我须要向领导请假,领导说你写个请假单,包含请假人的姓名,请假的起止时间,请假事由和代理人。因而我作了一个表格,包含了上述要求,并根据实际状况填入了真实信息。那么领导的描述,就能够理解为“建模”,而我最后提交的填好内容的表格,就是将模型实例化了。编程
2 建模须要什么呢
若是要建模,必定须要一些基础架构,而后将要创建的模型用这些基础架构拼接出来。那么YANG提供了哪些架构呢?数组
2.1 module和submodule
module的header主要是一些描述信息,而body就是data model定义的地方。module能够分为submodule。模块化的好处就是方便引用。session
2.2 Data Modeling Basics
这时候要敲敲黑板,由于重点来喽。这里介绍最最基本的四种建模架构。数据结构
2.2.1 Leaf Nodes
一个leaf node包含且只包含一个value,能够是数字或是字符串,具体是什么,看关键字"type"后面跟什么。leaf node下面不能挂子节点。
例如:架构
YANG Example: leaf host-name { type string; description "Hostname for this system"; } ----------------------- NETCONF XML Example: <host-name>my.example.com</host-name>
此处用YANG定义了一个名为host-name的leaf,它包含对本身的description,有一个string类型的值。那么当用XML实例化这个leaf的时候,就须要对host-name进行具体的赋值。换句话说,YANG是挖坑的,XML是填坑的,可是XML填坑用的材料的“形状”,要和YANG定义的同样。dom
2.2.2 Leaf-List Nodes
与上面的Leaf Nodes“一字之差”,多了一个“-list”。能够认为Leaf-List Nodes表示的是一个“数组”,“数组”中的元素的值的type必须保持一致,并且不能重复。
例如:ssh
YANG Example: leaf-list domain-search { type string; description "List of domain names to search"; } ----------------------- NETCONF XML Example: <domain-search>high.example.com</domain-search> <domain-search>low.example.com</domain-search> <domain-search>everywhere.example.com</domain-search>
和leaf node同样,它也只定义一个value,可是能够有一系列同类型的值。例子中<domain-serarch>的值有多个,可是定义和类型都是统一的。ide
2.2.3 Container Nodes
“Container”能够翻译成“集装箱”。真正有价值的,是集装箱里面装的货物,而不是集装箱自己。可是若是没有集装箱,那么里面的货物就散了。
Container的做用就是将数据层次化组织起来,呈现出subtree的样式。特别须要注意的是:
(1)一个空的集装箱也是能“卖钱”的,由于毕竟是铁皮作的,可是一个container自身是没有“value”的;
(2)一个集装箱容量是有限的,可是一个container能够装多少node并无限制,并且这些node能够在leaf/list/leaf-list甚至是container(想起了俄罗斯套娃)中任意选取。
例如:模块化
YANG Example: container system { container login { leaf message { type string; description "Message given at start of login session"; } } } ----------------------- NETCONF XML Example: <system> <login> <message>Good morning</message> </login> </system>
container system里面装了一个container login,而后login里面有一个leaf node,就是类型为string的“message”。
2.2.4 List Nodes
一个List node能够包含多个child node,并且这些node能够在leaf/leaf-list/container中任意选取。List必须指明这些child中的一个node为key。
例如:
YANG Example: list user { key "name"; leaf name { type string; } leaf full-name { type string; } leaf class { type string; } } ----------------------- NETCONF XML Example: <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>
定义了一个名为“user”的list,这个list中包含三个leaf:name/full-name/class。其中name被指定为key。实例化的时候,key的值(也就是"name"的值)是必须不一样的,其它的值(full-name/class)没有这个要求。随后xml实例化了三个user,都包含YANG定义的name/full-name/class,并且name都是不一样的。
2.2.5 Combined Module
RFC中给出了一个综合上述四种node的混合模式的例子以下:
// 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; } } } } } ----------------------- NETCONF XML Example: <system> <host-name>myyang.com</host-name> <domain-search>high.example.com</domain-search> <domain-search>low.example.com</domain-search> <domain-search>everywhere.example.com</domain-search> <login> <message>Good Morning</message> <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> </login> </system>
对YANG module的解读:
module的名字是acme-system
namespace是用来惟一标识这个YANG模型与其它YANG模型不一样
prefix是namespace的一种简写
organization/contact/description都是用来描述相关信息
revison描述版本信息,能够有多个revision(通常记录版本更新的内容)
module中包含一个container system
container system包含一个leaf(host-name),一个leaf-list(domain-search)和一个container login
container login包含一个leaf(message),和一个list(user)
下面的XML只要按照YANG Module的规定,实例化便可。
2.3 State Data
netconf须要区分configuration data和state(状态) data,在YANG建模的时候,对于state data须要加上"config false".例如:
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; } }
好吧,10m/100m确实暴露了这篇RFC的“年龄”,如今交换机的端口带宽已经能够达到100G甚至更高了。在list interface中。speed的value type是枚举类型,就是说实例化的时候只能从这里列出的三种中选择一个。对于leaf observed-speed,由于包含"config false",所以这个leaf记录的是state value,不能够配置。对应于netconf的操做,leaf speed能够<get-config>,而leaf observed-speed只能<get>。
2.4 Build-in Type
前面给leaf或是leaf-list定义类型的时候举的例子,type后面跟的都是string。实际上string只是YANG build-in(内建)数据类型中的一种。下面罗列一下YANG全部的build-in types
```
+---------------------+-------------------------------------+
| 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 |
+---------------------+-------------------------------------+
2.5 Derived Type 在实际建模中,上述的type确定是不够的。YANG容许用户使用typedef来定义本身须要的type,能够基于build-in type或是另一个派生的type。 例如须要一个描述百分比的type:
YANG Example:
typedef percent { type uint8 { range "0 .. 100"; } description "Percentage"; } leaf completed { type percent; }
NETCONF XML Example:
<completed>20</completed>
经过typedef定义了新的type"percent",基于uint8(0-255的无符号整数),并进一步限制取值范围为[0,100] 定义了leaf completed(完成百分比),使用的type正是上面定义的percent XML实例化completed时候给出的数值是20,符合percent的type定义 若是netconf交互的时候,completed传的数值若是不符合YANG的描述(例如小数/负数/200),会由于没法经过模型check而被拒绝 2.6 Reusable Node Groups (grouping) grouping其实不是一种数据类型,它存在的意义只是方便在“编程”的时候被引用。因此它自己是没有value的。grouping能够在本module被引用,或是被其它module引用。 grouping能够包含
+--------------+---------+-------------+
| 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 |
+--------------+---------+-------------+
例如:
YANG Example:
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; } }
NETCONF XML Example:
<peer> <destination> <address>192.0.2.1</address> <port>830</port> </destination> </peer>
回想一下,当一台主机对外提供服务的时候,客户端须要知道提供服务主机的的IP和端口信息。因此这边能够定义一个grouping target,在里面定义leaf address和leaf port。下面的container peer来uses(调用grouping的关键字)这个grouping。当对<peer>实例化的时候,就须要将grouping target中包含的address和port都进行赋值。这里的830端口,是在RFC6242(Using the NETCONF Protocol over Secure Shell)中定义的基于ssh的netconf服务端口。 这里的users能够理解为copy,即把grouping的整个内容都复制到了这个schema tree。grouping自己是没有绑定到任何namespace的,直到某个module uses了这个grouping,那么这个grouping就被绑定到这个module了。 grouping还有一个很是好用的特性就是refine,例如要创建链接,既须要server的IP+port,也须要client的IP+port。由于这两个的数据结构是彻底同样的,因此能够复用,并用更准确的description来覆盖grouping定义时候设置的description。
YANG Example:
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"; } } } }
2.7 Choices "choice"+"case"用来描述互斥的内容。一个choice能够包含多个case,每一个case能够包含多个node。通常来讲在一个choice里,一个case下面的node不该该和其余case下面的node重复。 在YANG模型和schema中能够看到choice下的全部case,而当对它实例化以后,只会出现一个case下面的nodes了。例如
YANG Example:
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; } } } } }
NETCONF XML Example:
<food> <pretzel/> <beer/> </food>
2.8 Extending Data Models (augment) YANG容许向data module插入新的节点。这是一个很是有用的特性,例如厂商想在公共yang上插入本身的特殊参数,那么augment就能够实现这个需求。"when"后面跟的是条件,即为知足这个条件,就插入新的node。例如
YANG Example:
augment /system/login/user { when "class != 'wheel'"; leaf uid { type uint16 { range "1000 .. 30000"; } } }
NETCONF XML Example 1:
<user> <name>alicew</name> <full-name>Alice N. Wonderland</full-name> <class>drop-out</class> <other:uid>1024</other:uid> </user>
NETCONF XML Example 2:
<user> <name>jerryr</name> <full-name>Jerry K. Roma</full-name> <class>wheel</class> </user>
Example 1中由于class不是"wheel",所以插入uid; Example 2中class是"wheel",因此不插入uid。 2.9 RPC Definitions YANG能够用来定义netconf的rpc,包括rpc输入的参数,输出的参数,例如:
YANG Example:
rpc activate-software-image { input { leaf image-name { type string; } } output { leaf status { type string; } } }
NETCONF XML Example:
<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>
定义一种叫作"activate-software-image"的rpc。当Client发送rpc的时候,须要加上image-name,交换机发回rpc-reply的时候,须要加上activate的结果,本例中能够看到操做是成功了。 2.10 Notification Definitions Notification是一种通告机制,当交换机上出现特性event(事件),交换机会主动发给已经创建netconf链接并订阅了Notification的client。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; } }
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>
这样不管是接口的admin状态(shutdown或是no shutdonw),仍是链路状态(down/up)发送改变的时候,均可以发送notification给client,而且带上了当前的状态信息。 3 学以至用 上面罗列了不少YANG语言建模的细节,可是还远远没有列全。可是若是仔细看了上面的内容,见到yang模型应该不会彻底手足无措了。例以下面列一个华为的huawei-netconf.yang来体会一下
/
Copyright (C) 2013-2017 Huawei Technologies Co., Ltd. All rights reserved.
/
module huawei-netconf {
namespace "http://www.huawei.com/netconf/vrp/huawei-netconf";
prefix netconf;
include huawei-netconf-type;
include huawei-netconf-authorization;
include huawei-netconf-notification;
include huawei-netconf-authorization-type;
include huawei-netconf-notification-type;
organization
"Huawei Technologies Co.,Ltd.";
contact
"Huawei Industrial Base Bantian, Longgang Shenzhen 518129
People's Republic of China
Website: http://www.huawei.com Email: support@huawei.com";
description
"The NETCONF protocol defines a simple mechanism through which a network device can be managed, configuration data information can be retrieved, and new configuration data can be uploaded and manipulated.";
revision 2017-03-23 {
description
"Functions supported by the schema are added to the YANG file.";
reference
"Huawei private.";
}
revision 2013-01-01 {
description
"Init revision";
reference
"Huawei private.";
}
container netconf {
description
"The NETCONF protocol defines a simple mechanism through which a network device can be managed, configuration data information can be retrieved, and new configuration data can be uploaded and manipulated.";
container netconfCapabilitys {
config false;
description
"NETCONF capability list.";
list netconfCapability {
key "capabilityName version";
config false;
description
"NETCONF capability.";
leaf capabilityName {
type netconfNcaCapability;
config false;
description
"Name of the NETCONF capability.";
}
leaf version {
type netconfCapabilityVersion;
config false;
description
"Capability version number.";
}
leaf scope {
type netconfCapabilityScope;
config false;
description
"Scope of the capability.";
}
}
}
container authorization {
description
"NETCONF authorization.";
uses netconf:netconf_authorization_type;
}
container notification {
config false;
description
"notification";
uses netconf:netconf_notification_type;
}
container operationLogSwitch {
description
"Switch for RPC oper log.";
leaf get {
type boolean;
description
"Get oper type.";
}
}
}
}
做者:ljyfree 连接:https://www.jianshu.com/p/ca7f5fe11fae 来源:简书 著做权归做者全部。商业转载请联系做者得到受权,非商业转载请注明出处。