YANG

1 为什么要有YANG
netconf需要对设备的配置(configuration)和状态(state)做操作,例如编辑配置,获取状态,因此需要一种语言来对configuration和state进行建模,甚至连“操作”也可以通过YANG来建模。建好的模型,最后以XML的形式进行实例化。打个比方,我需要向领导请假,领导说你写个请假单,包含请假人的姓名,请假的起止时间,请假事由和代理人。于是我做了一个表格,包含了上述要求,并根据实际情况填入了真实信息。那么领导的描述,就可以理解为“建模”,而我最后提交的填好内容的表格,就是将模型实例化了。

2 建模需要什么呢
如果要建模,一定需要一些基础架构,然后将要建立的模型用这些基础架构拼接出来。那么YANG提供了哪些架构呢?

2.1 module和submodule
module的header主要是一些描述信息,而body就是data model定义的地方。module可以分为submodule。模块化的好处就是方便引用。

2.2 Data Modeling Basics
这时候要敲敲黑板,因为重点来喽。这里介绍最最基本的四种建模架构。

2.2.1 Leaf Nodes
一个leaf node包含且只包含一个value,可以是数字或是字符串,具体是什么,看关键字"type"后面跟什么。leaf node下面不能挂子节点。
例如:

  1.  
       YANG Example:
  2.  
     
  3.  
           leaf host-name {
  4.  
               type string;
  5.  
               description "Hostname for this system";
  6.  
           }
  7.  
    -----------------------
  8.  
       NETCONF XML Example:
  9.  
     
  10.  
           <host-name>my.example.com</host-name>

此处用YANG定义了一个名为host-name的leaf,它包含对自己的description,有一个string类型的值。那么当用XML实例化这个leaf的时候,就需要对host-name进行具体的赋值。换句话说,YANG是挖坑的,XML是填坑的,但是XML填坑用的材料的“形状”,要和YANG定义的一样。

2.2.2 Leaf-List Nodes
与上面的Leaf Nodes“一字之差”,多了一个“-list”。可以认为Leaf-List Nodes表示的是一个“数组”,“数组”中的元素的值的type必须保持一致,而且不能重复。
例如:

  1.  
       YANG Example:
  2.  
     
  3.  
         leaf-list domain-search {
  4.  
             type string;
  5.  
             description "List of domain names to search";
  6.  
         }
  7.  
    -----------------------
  8.  
       NETCONF XML Example:
  9.  
     
  10.  
         <domain-search>high.example.com</domain-search>
  11.  
         <domain-search>low.example.com</domain-search>
  12.  
         <domain-search>everywhere.example.com</domain-search>

和leaf node一样,它也只定义一个value,但是可以有一系列同类型的值。例子中<domain-serarch>的值有多个,但是定义和类型都是统一的。

2.2.3 Container Nodes
“Container”可以翻译成“集装箱”。真正有价值的,是集装箱里面装的货物,而不是集装箱本身。但是如果没有集装箱,那么里面的货物就散了。
Container的作用就是将数据层次化组织起来,呈现出subtree的样式。特别需要注意的是:
(1)一个空的集装箱也是能“卖钱”的,因为毕竟是铁皮做的,但是一个container自身是没有“value”的;
(2)一个集装箱容量是有限的,但是一个container可以装多少node并没有限制,而且这些node可以在leaf/list/leaf-list甚至是container(想起了俄罗斯套娃)中任意选取。
例如:

  1.  
    YANG Example:
  2.  
     
  3.  
         container system {
  4.  
             container login {
  5.  
                 leaf message {
  6.  
                     type string;
  7.  
                     description
  8.  
                         "Message given at start of login session";
  9.  
                 }
  10.  
             }
  11.  
         }
  12.  
     
  13.  
    -----------------------
  14.  
       NETCONF XML Example:
  15.  
     
  16.  
         <system>
  17.  
           <login>
  18.  
             <message>Good morning</message>
  19.  
           </login>
  20.  
         </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。
例如:

  1.  
    YANG Example:
  2.  
     
  3.  
         list user {
  4.  
             key "name";
  5.  
             leaf name {
  6.  
                 type string;
  7.  
             }
  8.  
             leaf full-name {
  9.  
                 type string;
  10.  
             }
  11.  
             leaf class {
  12.  
                 type string;
  13.  
             }
  14.  
         }
  15.  
    -----------------------
  16.  
    NETCONF XML Example:
  17.  
     
  18.  
         <user>
  19.  
           <name>glocks</name>
  20.  
           <full-name>Goldie Locks</full-name>
  21.  
           <class>intruder</class>
  22.  
         </user>
  23.  
         <user>
  24.  
           <name>snowey</name>
  25.  
           <full-name>Snow White</full-name>
  26.  
           <class>free-loader</class>
  27.  
         </user>
  28.  
         <user>
  29.  
           <name>rzell</name>
  30.  
           <full-name>Rapun Zell</full-name>
  31.  
           <class>tower</class>
  32.  
         </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的混合模式的例子如下:

  1.  
    // Contents of "acme-system.yang"
  2.  
         module acme-system {
  3.  
             namespace "http://acme.example.com/system";
  4.  
             prefix "acme";
  5.  
     
  6.  
             organization "ACME Inc.";
  7.  
             contact "joe@acme.example.com";
  8.  
             description
  9.  
                 "The module for entities implementing the ACME system.";
  10.  
     
  11.  
             revision 2007-06-09 {
  12.  
                 description "Initial revision.";
  13.  
             }
  14.  
     
  15.  
             container system {
  16.  
                 leaf host-name {
  17.  
                     type string;
  18.  
                     description "Hostname for this system";
  19.  
                 }
  20.  
     
  21.  
                 leaf-list domain-search {
  22.  
                     type string;
  23.  
                     description "List of domain names to search";
  24.  
                 }
  25.  
     
  26.  
                 container login {
  27.  
                     leaf message {
  28.  
                         type string;
  29.  
                         description
  30.  
                             "Message given at start of login session";
  31.  
                     }
  32.  
     
  33.  
                     list user {
  34.  
                         key "name";
  35.  
                         leaf name {
  36.  
                             type string;
  37.  
                         }
  38.  
                         leaf full-name {
  39.  
                             type string;
  40.  
                         }
  41.  
                         leaf class {
  42.  
                             type string;
  43.  
                         }
  44.  
                     }
  45.  
                 }
  46.  
             }
  47.  
         }
  48.  
    -----------------------
  49.  
    NETCONF XML Example:
  50.  
     
  51.  
    <system>
  52.  
      <host-name>myyang.com</host-name>
  53.  
      <domain-search>high.example.com</domain-search>
  54.  
      <domain-search>low.example.com</domain-search>
  55.  
      <domain-search>everywhere.example.com</domain-search>
  56.  
      <login>
  57.  
        <message>Good Morning</message>
  58.  
        <user>
  59.  
           <name>glocks</name>
  60.  
           <full-name>Goldie Locks</full-name>
  61.  
           <class>intruder</class>
  62.  
         </user>
  63.  
         <user>
  64.  
           <name>snowey</name>
  65.  
           <full-name>Snow White</full-name>
  66.  
           <class>free-loader</class>
  67.  
         </user>
  68.  
         <user>
  69.  
           <name>rzell</name>
  70.  
           <full-name>Rapun Zell</full-name>
  71.  
           <class>tower</class>
  72.  
         </user>
  73.  
       </login>
  74.  
    </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".例如:

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

好吧,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

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


2.5 Derived Type
在实际建模中,上述的type肯定是不够的。YANG允许用户使用typedef来定义自己需要的type,可以基于build-in type或是另外一个派生的type。

例如需要一个描述百分比的type:

  1.  
     YANG Example:
  2.  
     
  3.  
         typedef percent {
  4.  
             type uint8 {
  5.  
                 range "0 .. 100";
  6.  
             }
  7.  
             description "Percentage";
  8.  
         }
  9.  
     
  10.  
         leaf completed {
  11.  
             type percent;
  12.  
         }
  13.  
    -----------------------
  14.  
       NETCONF XML Example:
  15.  
     
  16.  
         <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可以包含

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

例如:

  1.  
       YANG Example:
  2.  
     
  3.  
         grouping target {
  4.  
             leaf address {
  5.  
                 type inet:ip-address;
  6.  
                 description "Target IP address";
  7.  
             }
  8.  
             leaf port {
  9.  
                 type inet:port-number;
  10.  
                 description "Target port number";
  11.  
             }
  12.  
         }
  13.  
     
  14.  
         container peer {
  15.  
             container destination {
  16.  
                 uses target;
  17.  
             }
  18.  
         }
  19.  
    -----------------------
  20.  
       NETCONF XML Example:
  21.  
     
  22.  
         <peer>
  23.  
           <destination>
  24.  
             <address>192.0.2.1</address>
  25.  
             <port>830</port>
  26.  
           </destination>
  27.  
         </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。

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


2.7 Choices
"choice"+"case"用来描述互斥的内容。一个choice可以包含多个case,每个case可以包含多个node。一般来说在一个choice里,一个case下面的node不应该和其他case下面的node重复。

在YANG模型和schema中可以看到choice下的所有case,而当对它实例化之后,只会出现一个case下面的nodes了。例如

  1.  
       YANG Example:
  2.  
     
  3.  
         container food {
  4.  
           choice snack {
  5.  
               case sports-arena {
  6.  
                   leaf pretzel {
  7.  
                       type empty;
  8.  
                   }
  9.  
                   leaf beer {
  10.  
                       type empty;
  11.  
                   }
  12.  
               }
  13.  
               case late-night {
  14.  
                   leaf chocolate {
  15.  
                       type enumeration {
  16.  
                           enum dark;
  17.  
                           enum milk;
  18.  
                           enum first-available;
  19.  
                       }
  20.  
                   }
  21.  
               }
  22.  
           }
  23.  
        }
  24.  
    -----------------------
  25.  
       NETCONF XML Example:
  26.  
     
  27.  
         <food>
  28.  
           <pretzel/>
  29.  
           <beer/>
  30.  
         </food>


2.8 Extending Data Models (augment)
YANG允许向data module插入新的节点。这是一个非常有用的特性,例如厂商想在公共yang上插入自己的特殊参数,那么augment就可以实现这个需求。"when"后面跟的是条件,即为满足这个条件,就插入新的node。例如

 

  1.  
       YANG Example:
  2.  
     
  3.  
         augment /system/login/user {
  4.  
             when "class != 'wheel'";
  5.  
             leaf uid {
  6.  
                 type uint16 {
  7.  
                     range "1000 .. 30000";
  8.  
                 }
  9.  
             }
  10.  
         }
  11.  
    -----------------------
  12.  
       NETCONF XML Example 1:
  13.  
     
  14.  
         <user>
  15.  
           <name>alicew</name>
  16.  
           <full-name>Alice N. Wonderland</full-name>
  17.  
           <class>drop-out</class>
  18.  
           <other:uid>1024</other:uid>
  19.  
         </user>
  20.  
    -----------------------
  21.  
       NETCONF XML Example 2:
  22.  
     
  23.  
         <user>
  24.  
           <name>jerryr</name>
  25.  
           <full-name>Jerry K. Roma</full-name>
  26.  
           <class>wheel</class>
  27.  
         </user>

Example 1中因为class不是"wheel",因此插入uid; Example 2中class是"wheel",所以不插入uid。

2.9 RPC Definitions
YANG可以用来定义netconf的rpc,包括rpc输入的参数,输出的参数,例如:

  1.  
       YANG Example:
  2.  
     
  3.  
         rpc activate-software-image {
  4.  
             input {
  5.  
                 leaf image-name {
  6.  
                     type string;
  7.  
                 }
  8.  
             }
  9.  
             output {
  10.  
                 leaf status {
  11.  
                     type string;
  12.  
                 }
  13.  
             }
  14.  
         }
  15.  
    -----------------------
  16.  
       NETCONF XML Example:
  17.  
     
  18.  
         <rpc message-id="101"
  19.  
              xmlns="urn:ietf:params:xml:ns:netconf:base:1.0">
  20.  
           <activate-software-image xmlns="http://acme.example.com/system">
  21.  
             <image-name>acmefw-2.3</image-name>
  22.  
          </activate-software-image>
  23.  
         </rpc>
  24.  
     
  25.  
         <rpc-reply message-id="101"
  26.  
                    xmlns="urn:ietf:params:xml:ns:netconf:base:1.0">
  27.  
           <status xmlns="http://acme.example.com/system">
  28.  
             The image acmefw-2.3 is being installed.
  29.  
           </status>
  30.  
         </rpc-reply>

定义一种叫做"activate-software-image"的rpc。当Client发送rpc的时候,需要加上image-name,交换机发回rpc-reply的时候,需要加上activate的结果,本例中可以看到操作是成功了。

2.10 Notification Definitions
Notification是一种通告机制,当交换机上出现特性event(事件),交换机会主动发给已经建立netconf连接并订阅了Notification的client。YANG可以定义notification,例如

  1.  
       YANG Example:
  2.  
     
  3.  
         notification link-failure {
  4.  
             description "A link failure has been detected";
  5.  
             leaf if-name {
  6.  
                 type leafref {
  7.  
                     path "/interface/name";
  8.  
                 }
  9.  
             }
  10.  
             leaf if-admin-status {
  11.  
                 type admin-status;
  12.  
             }
  13.  
             leaf if-oper-status {
  14.  
                 type oper-status;
  15.  
             }
  16.  
         }
  17.  
    -----------------------
  18.  
       NETCONF XML Example:
  19.  
     
  20.  
         <notification
  21.  
             xmlns="urn:ietf:params:netconf:capability:notification:1.0">
  22.  
           <eventTime>2007-09-01T10:00:00Z</eventTime>
  23.  
           <link-failure xmlns="http://acme.example.com/system">
  24.  
             <if-name>so-1/2/3.0</if-name>
  25.  
             <if-admin-status>up</if-admin-status>
  26.  
             <if-oper-status>down</if-oper-status>
  27.  
           </link-failure>
  28.  
         </notification>

这样无论是接口的admin状态(shutdown或是no shutdonw),还是链路状态(down/up)发送改变的时候,都可以发送notification给client,并且带上了当前的状态信息。

3 学以致用
上面罗列了很多YANG语言建模的细节,但是还远远没有列全。但是如果仔细看了上面的内容,见到yang模型应该不会完全手足无措了。例如下面列一个华为的huawei-netconf.yang来体会一下

  1.  
    /*
  2.  
    Copyright (C) 2013-2017 Huawei Technologies Co., Ltd. All rights reserved.
  3.  
    */
  4.  
    module huawei-netconf {
  5.  
      namespace "http://www.huawei.com/netconf/vrp/huawei-netconf";
  6.  
      prefix netconf;
  7.  
      include huawei-netconf-type;
  8.  
      include huawei-netconf-authorization;
  9.  
      include huawei-netconf-notification;
  10.  
      include huawei-netconf-authorization-type;
  11.  
      include huawei-netconf-notification-type;
  12.  
      
  13.  
      organization
  14.  
        "Huawei Technologies Co.,Ltd.";
  15.  
      contact
  16.  
        "Huawei Industrial Base Bantian, Longgang Shenzhen 518129                    
  17.  
            People's Republic of China                    
  18.  
            Website: http://www.huawei.com Email: support@huawei.com";
  19.  
      description
  20.  
        "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.";
  21.  
      revision 2017-03-23 {
  22.  
        description
  23.  
          "Functions supported by the schema are added to the YANG file.";
  24.  
        reference
  25.  
          "Huawei private.";
  26.  
      }
  27.  
      revision 2013-01-01 {
  28.  
        description
  29.  
          "Init revision";
  30.  
        reference
  31.  
          "Huawei private.";
  32.  
      }
  33.  
      container netconf {
  34.  
        description
  35.  
          "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.";
  36.  
        container netconfCapabilitys {
  37.  
          config false;
  38.  
          description
  39.  
            "NETCONF capability list.";
  40.  
          list netconfCapability {
  41.  
            key "capabilityName version";
  42.  
            config false;
  43.  
            description
  44.  
              "NETCONF capability.";
  45.  
            leaf capabilityName {
  46.  
              type netconfNcaCapability;
  47.  
              config false;
  48.  
              description
  49.  
                "Name of the NETCONF capability.";
  50.  
            }
  51.  
            leaf version {
  52.  
              type netconfCapabilityVersion;
  53.  
              config false;
  54.  
              description
  55.  
                "Capability version number.";
  56.  
            }
  57.  
            leaf scope {
  58.  
              type netconfCapabilityScope;
  59.  
              config false;
  60.  
              description
  61.  
                "Scope of the capability.";
  62.  
            }
  63.  
          }
  64.  
        }
  65.  
        container authorization {
  66.  
          description
  67.  
            "NETCONF authorization.";
  68.  
          uses netconf:netconf_authorization_type;
  69.  
        }
  70.  
        container notification {
  71.  
          config false;
  72.  
          description
  73.  
            "notification";
  74.  
          uses netconf:netconf_notification_type;
  75.  
        }
  76.  
        container operationLogSwitch {
  77.  
          description
  78.  
            "Switch for RPC oper log.";
  79.  
          leaf get {
  80.  
            type boolean;
  81.  
            description
  82.  
              "Get oper type.";
  83.  
          }
  84.  
        }
  85.  
      }
  86.  
    }

 

posted @ 2021-11-18 16:02  常给自己加个油  阅读(220)  评论(0编辑  收藏  举报