天天看點

YANG模型對YANG的解讀(一)1 為什麼要有YANG2 模組化需要什麼呢3 學以緻用

對YANG的解讀(一)

https://www.jianshu.com/p/ca7f5fe11fae

https://www.sdnlab.com/18066.html

https://blog.csdn.net/dolphin98629/article/details/54906208

在研究netconf的時候,YANG(RFC6020)是一定繞不過的。花了一些時間看RFC6020,有一點初步的了解,記錄下來友善後面檢視。

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下面不能挂子節點。

例如:

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定義的一樣。

2.2.2 Leaf-List Nodes

與上面的Leaf Nodes“一字之差”,多了一個“-list”。可以認為Leaf-List Nodes表示的是一個“數組”,“數組”中的元素的值的type必須保持一緻,而且不能重複。

例如:

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>的值有多個,但是定義和類型都是統一的。

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 "[email protected]";
         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: [email protected]";
  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.";
      }
    }
  }
}
           

小禮物走一走,來簡書關注我