數據模型與網絡自動化

傳統人工 CLI 配置網絡的模式,已經不在適用當代的網絡,面臨着兼容性,容錯率低,效率低下等等問題,詳細的內容可閱讀這篇傳統CLI面臨的挑戰

在這樣的大背景下,各種網管協議應運而生。但這時就產生一個問題,以怎樣的格式和內容去傳遞配置?

YANG 就是爲了解決該問題而出現的,在解釋 YANG 前,我們先來回憶下,傳統 CLI 是如何下發配置的?

常常是由網絡工程師通過 console/Telnet/SSH 等方式登錄上設備,然後直接對設備進行配置,這時自然不用考慮怎樣傳參的問題,只要懂得設備的命令,直接上去敲就可以。

而 CLI 這樣的配置,是一種無結構化的數據。

!
interface Bundle-Ether2
!
interface Bundle-Ether780
 description evpn-vpws-test
!
interface MgmtEth0/RSP0/CPU0/0
 vrf mgmt
 ipv4 address 10.124.3.85 255.255.255.0
!
interface MgmtEth0/RSP0/CPU0/1
 shutdown
!
interface TenGigE0/0/1/0
 shutdown
!
interface TenGigE0/0/1/1
 shutdown
!
interface TenGigE0/0/2/0
 shutdown
!

這樣無結構的數據對我們人來說是非常友好的,容易理解和閱讀。

但由於換成了 NETCONF 這樣的網管協議管理設備,這樣的數據發揮不出任何優勢,甚至無法被機器識別。因爲使用 NETCONF 目的就是爲了使用自動化,可編程化的方案代替人工,從而滿足當下網絡的各種業務場景。

此時配置結構化的數據就成了必然。

於是各個廠商開始對配置進行結構化的約定,在 NETOCNF 中,配置使用 XML 表示,進行參數的下發。

比如對接口的 MTU 進行更改:

 <rpc message-id="101" xmlns="urn:ietf:params:xml:ns:netconf:base:1.0">
       <edit-config>
         <target>
           <running/>
         </target>
         <config>
           <top xmlns="http://example.com/schema/1.2/config">
             <interface>
               <name>Ethernet0/0</name>
               <mtu>1500</mtu>
             </interface>
           </top>
         </config>
       </edit-config>
</rpc>

但此時又有一個問題,就是下發數據的格式和參數是由誰指定呢,比如這裏 interface 命名的定義,類型的定義,層級的定義是如何確定的呢?

我怎麼知道在下發接口配置時,就下發這樣的配置內容呢?

答案在於各個廠商定義了一套約束標準,也可以理解成配置的模板。這些模板對數據進行約束,判斷是否是合法的數據。這也就是數據模型的由來。

拿 NETCONF 舉例,NETCONF 採用 C/S 的架構,Client 端在生成配置內容時會參考定義好的數據模型。Server 在接收時,同樣會用這些數據模型進行校驗。

具體些,比如針對下發 JSON 格式的配置,通過 JSON Scheme 定義的 JSD 對數據進行約束。

如左圖中是具體的數據,右圖中是對左側數據具體進行約束的數據模型。比如這裏限定了,productName 的類型是字符串,當前對象共有三個屬性等。當傳入其他不符合 scheme 的數據時,會進行的報錯。

如果對 JSON-Scheme 感興趣,可以去官網仔細瞭解下。

對於思科設備來說,這種由 JSON-Scheme 定義的文件叫 JSD,用於約束傳入的數據類型,需要注意的是不同的廠商定義的 JSD 內容和格式是不一樣的,甚至同一廠商定義的不同類型的 JSD 也不一樣。

針對下發的 XML 格式的配置也採用相同的方法,各個廠商通過 XML Scheme 定義 XSD 對數據進行約束。

左面是 xml 格式的數據,右邊是 XSD 文件對其進行約束,規定了屬性的類型。同樣不同廠商編寫的 XSD 約束也是不一樣的。

雖然說通過編寫 XSD 和 JSD 的方式解決了如何約束配置數據的問題。

但由於不同廠商編寫的數據模型沒有統一的規範,導致各種各樣的 JSD/XSD 出現,學習成本也很高。而且造成很嚴重的兼容性問題。比如 Cisco 的 JSD 或者 XSD 一定和 HUAWEI 不一樣。甚至 Cisco 本身每個團隊開發出的 JSD/XSD 的內容也不一樣。

爲了解決這個問題,由 IETF 主導,開發出了 YANG - Yet Another Next Generation. 被現在各個協議廣泛使用。

YANG

YANG 的定義

YANG 是一種數據模型語言,用於在 NETCONF 等網絡協議中,將想要操作的配置或狀態數據進行模型化,用層次化的表現形式,對數據進行表述。對於 YANG 模型來說,每個都有唯一標識命名空間 URI,用於區分。

簡單來說,通過 YANG,對下發配置的進行約束,如下的公式很好的描述了 YANG:

data(下發的數據)+ YANG = 下發給設備的配置

上圖中很好的表示了 YANG 起到的作用,YANG 本身並不是數據,而更像是一種配置模板,起到約束數據的作用。

那麼 YANG Model 一般是由誰定義的呢?

YANG Model 的定義,主要有兩個角色:

  • 標準化的 YANG Model ,由 IETF,OpenConfig 等機構進行規劃定義。這類的 YANG 主要是考慮到多嘗試的兼容性問題,而推出的統一的 YANG Module。所有廠商都需要支持。

  • 各個廠商實現自定義私有的 YANG。這類 YANG Model 主要是爲了廠商實現某些私有或特有功能 YANG. 比如 Cisco 中有許多私有的協議,如 EIGRP,BGP 的某些功能只有思科設備上有。

YANG 的結構

YANG Module 以層次化樹形結構被組織起來,每個模塊可以引入外部其他的模塊,包含其子模塊的數據。

簡單來說,就是可以將模塊作爲參數,引入其他的模塊進行使用。

YANG 定義了很多的內置類型,並提供了自定義類型的機制,類似於 C 中的 typedef.

在 YANG 中定義了四種類型,用於將數據模型化:

Leaf Nodes:

一個節點用於表示數字或字符串等簡單的數據。但只能表示一個值,不能擁有子節點。

YANG 表示:

 leaf host-name {
           type string;
           description "Hostname for this system";
       }

xml 表示:

 <host-name>my.example.com</host-name>

json 表示:

{
    "host-name": "my.example.com"
}

Leaf-List Nodes:

表示由 leaf node 構成的列表。

YANG 表示:

 leaf-list domain-search {
         type string;
         description "List of domain names to search";
     }

xml 表示:

<domain-search>high.example.com</domain-search>
<domain-search>low.example.com</domain-search>
<domain-search>everywhere.example.com</domain-search>

json 表示:

[
{"domain-search": "high.example.com"},
{"domain-search": "low.example.com"},
{"domain-search": "everywhere.example.com"},
]

Container Nodes:

類似於編程語言中的 MAP 形式,將多個 node 組裝到一起。一個 container node 可以包含多個任意類型的 node 節點,如 leafs,lists,leaf-lists,及本身 container 的類型。

YANG 表示:

 container system {
         container login {
             leaf message {
                 type string;
                 description
                     "Message given at start of login session";
             }
         }
     }

xml 表示:

 <system>
       <login>
         <message>Good morning</message>
       </login>
     </system>

json 表示:

{"system":{"login": {"message": "Good morning"}}}

List Nodes

由一個或多個 key leaf 和多個任意類型的子節點組成,類型包括,leafs,
lists, containers 等。

其中 key leaf 用於表示當前 list 的唯一性。

YANG 表示:

 list user {
         key "name";
         leaf name {
             type string;
         }
         leaf full-name {
             type string;
         }
         leaf class {
             type string;
         }
     }

這裏的 name 作爲唯一的標識符。

xml 表示:

     <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>

List Nodes 和 Leaf-List Nodes 的區別就是,Leaf-List Nodes 僅能包含類型是 Leaf Nodes 的節點,而 List Nodes 可以包含任意類型。

YANG 的其他特性

對於 YANG 來說,本身支持很多特性:

  • 配置狀態數據,對於定義那些不能配置的配置信息。

  • 內置大量的基礎類型,binary,bits,boolean 等等。

  • 派生類型,自定義去定義如 binary 等類型。

  • 可重用組,引用通過 grouping 陳述定義的組,用於解耦和封裝。

  • 支持 choices,類似於枚舉。

  • 使用 augment 對 model 進行約束

  • 提供 RPC 調用

  • 提供通知定義

更多的功能,可以參考 YANG - RFC 文檔

PYANG - 更好的瀏覽 YANG Model

在瞭解 YANG 語言,提供的強大功能後。一般在項目中,會使用由 Python 開發的 Pyang 工具來瀏覽 YANG 模型.

簡單提一下安裝方法,目前 Pyang 支持 Python2,Python3.

可以通過 docker 打包 Python 鏡像後,作爲運行環境:

[root@localhost pyang-env]# ls
Dockerfile  requirements.txt  yang_modules

[root@localhost pyang-env]# cat Dockerfile
FROM python:3.8.5

ENV MY_PROXY_URL="http://xxx:80"
ENV HTTP_PROXY=$MY_PROXY_URL \
    HTTPS_PROXY=$MY_PROXY_URL \
    FTP_PROXY=$MY_PROXY_URL \
    http_proxy=$MY_PROXY_URL \
    https_proxy=$MY_PROXY_URL \
    ftp_proxy=$MY_PROXY_URL

WORKDIR /src

COPY ./requirements.txt /

RUN pip install --no-cache-dir  pyang

ENV MY_PROXY_URL=
ENV HTTP_PROXY=$MY_PROXY_URL \
    HTTPS_PROXY=$MY_PROXY_URL \
    FTP_PROXY=$MY_PROXY_URL \
    http_proxy=$MY_PROXY_URL \
    https_proxy=$MY_PROXY_URL \
    ftp_proxy=$MY_PROXY_URL

使用 docker run -v /home/xx/pyang-env/yang_modules:/src -it --name pyang-env pyang-image /bin/bash 啓動運行環境。

接着去 YANG 的 Github 中,下載由 IETF 或各個廠商開發後的 YANG Module 。這裏以 IOS-XE 版本爲 633 的 YANG Module 爲例。

可以看到有很多類似的 YANG 文件:

這時就可以通過 Pyang 工具,來瀏覽內容:

root@a8af90280cf1:/src/633# pyang -f tree ietf-interfaces.yang
module: ietf-interfaces
  +--rw interfaces
  |  +--rw interface* [name]
  |     +--rw name                        string
  |     +--rw description?                string
  |     +--rw type                        identityref
  |     +--rw enabled?                    boolean
  |     +--rw link-up-down-trap-enable?   enumeration {if-mib}?
  +--ro interfaces-state
     +--ro interface* [name]
        +--ro name               string
        +--ro type               identityref
        +--ro admin-status       enumeration {if-mib}?
        +--ro oper-status        enumeration
        +--ro last-change?       yang:date-and-time
        +--ro if-index           int32 {if-mib}?
        +--ro phys-address?      yang:phys-address
        +--ro higher-layer-if*   interface-state-ref
        +--ro lower-layer-if*    interface-state-ref
        +--ro speed?             yang:gauge64
        +--ro statistics
           +--ro discontinuity-time    yang:date-and-time
           +--ro in-octets?            yang:counter64
           +--ro in-unicast-pkts?      yang:counter64
           +--ro in-broadcast-pkts?    yang:counter64
           +--ro in-multicast-pkts?    yang:counter64
           +--ro in-discards?          yang:counter32
           +--ro in-errors?            yang:counter32
           +--ro in-unknown-protos?    yang:counter32
           +--ro out-octets?           yang:counter64
           +--ro out-unicast-pkts?     yang:counter64
           +--ro out-broadcast-pkts?   yang:counter64
           +--ro out-multicast-pkts?   yang:counter64
           +--ro out-discards?         yang:counter32
           +--ro out-errors?           yang:counter32

還可以轉換成 js 瀏覽:

pyang -f jstree ietf-interfaces.yang >> ietf-interfaces.html

更多命令可以查看幫助文檔。

這時,對於網絡工程師來說,可以將其從學習各廠商不同的配置命令轉化到學習 Yang Module 中,更加聚焦功能,而不用在花費時間去學習相同的功能不同的命令。

YANG-Suite 介紹

YANG-Explorer 是一個用於瀏覽 YANG Model 的 WEB 服務,並提供生成 NETCONF RPC payload 等實用的功能。但由於其使用 Flash 編寫,但在 2020 12 月後,Flash 已經被禁用,導致該工具無法使用。有興趣的同學,可以安裝老版本帶 flash 的瀏覽器測試學習。

安裝可以採用 docker:

YANG

docker pull robertcsapo/yang-explorer

docker run -it --rm -p 8088:8088 robertcsapo/yang-explorer

最新 CISCO 很開源了一個產品爲 YANG-Suite,基於 YANG-Explorer 拓展了許多功能,並可以使用 docker-compose 啓動,兼容性更好,預計未來會主流接受。

比如下面使用其生成 NETCONF RPC Payload

Screenshot showing the selected YangModel, various parameters such as the selected value, mode, datastore, and RPC window with the RPC textbox displaying the RPC

YANG 與 NETCONF

YANG 在早期是專爲 NETCONF 而開發的一種語言,後來才被普及到各個語言中,關於 NETCONF 的介紹,可以參考這篇。

下面主要涉及具體的操作,使用的設備是 ASR9000(IOS-XR 6.3.3)版本。

由於 NETCONF 本身採用 C/S 架構,需要在設備端打開:

netconf agent ssh

在客戶端方面,可以使用 ssh 進行測試:

NETCONF 會首先使用 Hello 建立鏈接,報告所擁有的能力。

[root@localhost ~]# ssh cisco@ip -p 830 -s netconf

Password:
<hello xmlns="urn:ietf:params:xml:ns:netconf:base:1.0">
 <capabilities>
  <capability>urn:ietf:params:netconf:base:1.1</capability>
  <capability>urn:ietf:params:netconf:capability:candidate:1.0</capability>
  <capability>urn:ietf:params:netconf:capability:rollback-on-error:1.0</capability>
  <capability>urn:ietf:params:netconf:capability:validate:1.1</capability>
  <capability>urn:ietf:params:netconf:capability:confirmed-commit:1.1</capability>
  <capability>urn:ietf:params:netconf:capability:notification:1.0</capability>
  <capability>urn:ietf:params:netconf:capability:interleave:1.0</capability>
  <capability>urn:ietf:params:xml:ns:yang:ietf-netconf-monitoring?module=ietf-netconf-monitoring&amp;revision=2010-10-04&amp;deviations=cisco-xr-ietf-netconf-monitoring-deviations</capability>
  <capability>http://cisco.com/ns/yang/cisco-xr-ietf-netconf-monitoring-deviations?module=cisco-xr-ietf-netconf-monitoring-deviations&amp;revision=2016-02-16</capability>
  <capability>http://cisco.com/ns/yang/Cisco-IOS-XR-Ethernet-SPAN-cfg?module=Cisco-IOS-XR-Ethernet-SPAN-cfg&amp;revision=2015-11-09</capability>
  <capability>http://cisco.com/ns/yang/Cisco-IOS-XR-Ethernet-SPAN-datatypes?module=Cisco-IOS-XR-Ethernet-SPAN-datatypes&amp;revision=2015-11-09</capability>
  <capability>http://cisco.com/ns/yang/Cisco-IOS-X

每個 capability 都可包含四部分內容:

  • Model URI
  • Module Name ,Revision Date
  • Protocol Features
  • Deviations - 修改自那個 Module
 <capability>urn:ietf:params:xml:ns:yang:ietf-netconf-monitoring?module=ietf-netconf-monitoring&amp;revision=2010-10-04&amp;deviations=cisco-xr-ietf-netconf-monitoring-deviations</capability>
 
 Model URI = urn:ietf:params:xml:ns:yang:ietf-netconf-monitoring
 Module Name = module=ietf-netconf-monitoring
 Revision = 2010-10-04
 Protocol Features = NULL
 Deviations = cisco-xr-ietf-netconf-monitoring-deviations

使用 ncclient 操作 NETCONF 設備, 使用參見 ncclient-github

獲取 running 配置:

from ncclient import manager

host = "10.1.1.22"
username = "cisco"
password = "cisco"
device_params = {"name": "iosxr"}

with manager.connect(host=host, port=830, username=user, hostkey_verify=False, password=password) as m:
    c = m.get_config(source='running').data_xml
    with open("%s.xml" % host, 'w') as f:
        f.write(c)

上面演示了 NETCONF 中 get-config 操作,其餘配置或過濾的功能,可參考文檔。

需要注意一點的是,在配置時,payload 的生成一般通過上面介紹的 YANG-Suite 工具。

YANG 與 RESTCONF

RESTCONF 和 NETCONF 很像,簡單來說,就是將 HTTP 融入了 NETCONF 中,採用 REST 風格替代 SSH 和 RPC 的交互方式。

更詳細的內容,可參看這一篇。RESTCONF,下面主要集中在具體操作。

先來看下 RESTCONF URL 的內容:

https://<ADDRESS>/<ROOT>/<DATASTORE>/[YANGMODULE:]CONTAINER/<LEAF>[?<OPTIONS>]
  • ADDRESS:表示 RESTCONF 代理的 IP
  • ROOT:表示 restconf 請求的入口點
  • DATASTORE:被查詢的數據庫
  • [YANGMODULE:]CONTAINER - 使用基礎的模塊名稱
  • : 在 Container 內的獨立 node
  • ?:返回結果的過濾參數

這裏以 NSO - 思科的產品爲例,直接操作設備也同理,比如 IOS-XE 的設備。

首先查詢是否具有 RESTCONF 功能:

http://xx:8080/.well-known/host-meta

# Response 包含具有 RESTCONF 內容 
<XRD xmlns='http://docs.oasis-open.org/ns/xri/xrd-1.0'>
    <Link rel='restconf' href='/restconf'/>
</XRD>

# 裏面的內容表示 ROOT 的內容,作爲 RESTCONF 的入口點。

查看 NETCONF 支持的能力:

http://xx:8080/restconf/data/netconf-state/

查看 RESTCONF 支持的能力:

http://xx:8080/restconf/data/restconf-state/

NOTE:

需要在 Headers 中,指定發送和接受數據的格式:

Content-type:

  • application/yang-data+json
  • application/yang-data+xml

Accept:

  • application/yang-data+json
  • application/yang-data+xml

查詢 NSO 納管的設備 - GET Method:

http://10.124.207.154:8080/restconf/data/tailf-ncs:devices/device=ASR9K/name/

修改接口描述 - Patch Method:

http://10.124.207.154:8080/restconf/data/tailf-ncs:devices/device=ASR9K/config/tailf-ned-cisco-ios-xr:interface/TenGigE/

{
    "tailf-ned-cisco-ios-xr:TenGigE": 
        {
            "id": "0/0/1/0",
            "description": "restconf-test"
        }
}

總結

YANG 的本質是一種對數據進行結構化描述的語言,本身不是數據,而是起到約束數據的作用。

至於爲什麼需要 YANG,原因在於傳統 CLI 的方式,不在適合當代網絡的要求。而且結構化,統一的數據更容易被機器所處理。

現在 YANG 被廣泛使用,特別是可編程化的特點,像讓自動化,動態編排服務,甚至網絡自我調節與優化都成爲了可能。

下圖中很好的描述了 YANG 所發揮的作用,在設備上通過 YANG 的定義,提供如 RESTCONF,NETCONF 的接口,讓其通過 HTTP 或 RPC 管理設備。

在控制器中,根據定義的 YANG Module 來開發各種客戶端,去調用設備。

Cisco Connect Toronto 2018 model-driven programmability for cisco i…

參考

RFC6020 - YANG

RFC6020 - YANG1.1

YANG-Study

YANG Models

yang-explorer

RESTCONF-URL

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章