1. 介绍
YANG 是一种用于为 NETCONF 协议建模数据的语言。
YANG 将数据的层次结构建模为一棵树。
2. 节点类型
2.1 leaf
它只有一个特定类型的值,并且没有子节点。
YANG EXAMPLE:
leaf host-name { type string; description "Hostname for this system"; }
NETCONF XML Example:
<host-name>my.example.com</host-name>
2.2 leaf-list
就是一系列的 leaf 节点。
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>
2.3 container
将相关的节点组成一棵子树。
它只有子节点,而没有值。
一个 container 节点可以包含任意数量的任意类型的子节点(包括 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>
2.4 list
list 定义了一系列的列表条目。每个条目类似于一个结构实例,并由其 key leaf 的 key 唯一标识。
list 可以定义多个 key leaf,并且可以包含任意数量的任何类型的子节点(包括 list)。
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>
3. 数据类型
3.1 内建类型
类型 | 描述 |
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 |
3.1.1 bit和bits
bit 语句用于每个比特位指定一个名字。
bit 语句的 position 子句指定要使用的比特位的位置。
leaf mybits { type bits { bit disable-nagle { position 0; } bit auto-sense-speed { position 1; } bit 10-Mb-only { position 2; } } default "auto-sense-speed"; }
<mybits>disable-nagle 10-Mb-only</mybits>
3.1.2 数字类型和range
使用 decimal64 类型时,必须使用 fraction-digits 来指定要精确到小数点后几位(1~18)。
可以使用 range 语句来限定数字类型有效的取值范围。
typedef my-base-int32-type { type int32 { range "1..4 | 10..20"; } } typedef my-type1 { type my-base-int32-type { range "11..max"; // 11..20 } } typedef my-decimal { type decimal64 { fraction-digits 2; range "1 .. 3.14 | 10 | 20..max"; } }
3.1.3 enum和enumeration
enum 语句用于指定可选的枚举值。
可以使用 enum 语句的 value 子句为枚举值指定一个整数。
leaf myenum { type enumeration { enum zero; enum one; enum seven { value 7; } } }
<myenum>seven</myenum>
3.1.4 identity和identityref
identity 语句用于定义一个全局唯一的、抽象的、没有标注类型的 identity。其目的是定义一个名称、语义。
可以使用 base 子句来派生一个已有的 identity:
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"; } }
identityref 用于引用一个已经存在的 identify。
该类型有效的值是:任何派生自指定 identity 的 identities。
module my-crypto { namespace "http://example.com/my-crypto"; prefix mc; import "crypto-base" { prefix "crypto"; } identity aes { base "crypto:crypto-alg"; } leaf crypto { type identityref { base "crypto:crypto-alg"; } } }
<crypto xmlns:des="http://example.com/des">des:des3</crypto>
3.1.5 instance-identifier
用于唯一标识数据树中的某个节点实例。
使用 XPath 语法。
module example { namespace "ii:example"; prefix "ex"; container system { description "Contains various system parameters"; container services { description "Configure externally available services"; container "ssh" { leaf port { type uint16; } leaf-list cipher { type string; ordered-by user; description "A list of ciphers"; } } } list server { key "name"; unique "ip port"; leaf name { type string; } leaf ip { type inet:ip-address; } leaf port { type inet:port-number; } } 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; } } container stats { list ports { leaf port-number { type uint16; } leaf port-status { type uint16; } } } } }View Code
/* instance-identifier for a container */ /ex:system/ex:services/ex:ssh /* instance-identifier for a leaf */ /ex:system/ex:services/ex:ssh/ex:port /* instance-identifier for a list entry */ /ex:system/ex:user[ex:name='fred'] /* instance-identifier for a leaf in a list entry */ /ex:system/ex:user[ex:name='fred']/ex:type /* instance-identifier for a list entry with two keys */ /ex:system/ex:server[ex:ip='192.0.2.1'][ex:port='80'] /* instance-identifier for a leaf-list entry */ /ex:system/ex:services/ex:ssh/ex:cipher[.='blowfish-cbc'] /* instance-identifier for a list entry without keys */ /ex:stats/ex:port[3]
3.1.6 leafref
用于引用数据树中的某个 leaf 实例。
使用 type 语句的 path 子句指定要引用哪个 leaf。
list interface { key "name"; leaf name { type string; } leaf admin-status { type admin-status; } list address { key "ip"; leaf ip { type yang:ip-address; } } } leaf mgmt-interface { type leafref { path "../interface/name"; } }
3.1.7 string
可以使用 length 子句来限定字符串的字符个数。
typedef my-base-str-type { type string { length "1..255"; } } type my-base-str-type { // legal length refinement length "11 | 42..max"; // 11 | 42..255 }
可以使用 pattern 子句来限定字符串必须匹配的模式。
type string { length "0..4"; pattern "[0-9a-fA-F]*"; }
3.1.8 union
类似于 C 语言中的 union,一次只有一个成员有效。
type union { type int32; type enumeration { enum "unbounded"; } }
3.2 派生类型
从基类型派生出新的类型。基类型可以是内建类型,也可以是另一个派生类型。
派生类型使用 typedef 语句定义;typedef 的 type 子句定义了该派生类型的基类型,default 子句定义了该类型的默认值。
YANG EXAMPLE:
typedef percent { type uint8 { range "0 .. 100"; } default 0; description "Percentage"; } leaf completed { type percent; }
NETCONF XML Example:
<completed>20</completed>
4. 重用节点
使用 grouping 定义一个节点组,使用 use 实例化节点。
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>
在 use 节点组的时候,可以对节点进行 refine:
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"; } } } }
5. choice...case
一个 choice 语句包含多个 case 子句。
当某个 case 被选中时,其他 case 中的节点将被移除。
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>
6. 状态数据和配置数据
当一个节点包含 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; } }
7. 扩展数据模型
augment 定义了在数据模型层级结构的哪个地方插入新节点;
when 定义了新节点在什么条件下有效。
YANG EXAMPLE:
augment /system/login/user { when "class != 'wheel'"; leaf uid { type uint16 { range "1000 .. 30000"; } } }
NETCONF XML Example:
<user> <name>alicew</name> <full-name>Alice N. Wonderland</full-name> <class>drop-out</class> <other:uid>1024</other:uid> </user>
8. 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>
9. 通知定义
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>
10. 模块和子模块
一个 module 定义了一个数据模型。一个 module 可以包含多个 submodule,一个 submodule 必须属于某个 module。
一个 module/submodule 可以使用 include 语句包含其他 submodule,使用 import 语句引用外部 module。
import 和 include 的另一个区别如下:
- module A import 了 module B,当 B 更新时,A 不受影响;
- module A include 了 submodule SB,当 SB 更新时,A 也会相应地更新。
module 的 prefix 语句定义了访问该 module 所使用的前缀:prefix:module。
import 语句的 prefix 子句指定了使用导入模块时所需使用的前缀。
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... }
submodule 使用 belongs-to 语句来说明该 submodule 属于哪个 module。belongs-to 语句的 prefix 子句指定了使用该 submodule 时所需使用的前缀。
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... }
参考资料
https://tools.ietf.org/html/rfc6020