傳統人工 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,類似于枚舉。
- 使用
對 model 進行限制augment
- 提供 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&revision=2010-10-04&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&revision=2016-02-16</capability>
<capability>http://cisco.com/ns/yang/Cisco-IOS-XR-Ethernet-SPAN-cfg?module=Cisco-IOS-XR-Ethernet-SPAN-cfg&revision=2015-11-09</capability>
<capability>http://cisco.com/ns/yang/Cisco-IOS-XR-Ethernet-SPAN-datatypes?module=Cisco-IOS-XR-Ethernet-SPAN-datatypes&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&revision=2010-10-04&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:
Accept:
- application/yang-data+json
- application/yang-data+xml
- 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