理解YANG

原文連接: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
來源:簡書
著做權歸做者全部。商業轉載請聯繫做者得到受權,非商業轉載請註明出處。
相關文章
相關標籤/搜索