天天看點

資料模型與網絡自動化

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

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

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

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

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

!
interface Bundle-Ether2
!
interface Bundle-Ether780
 description e***-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

資料模型與網絡自動化

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 來開發各種用戶端,去調用裝置。

參考

RFC6020 - YANG

RFC6020 - YANG1.1

YANG-Study

YANG Models

yang-explorer

RESTCONF-URL

繼續閱讀