摘自:https://blog.csdn.net/weixin_30453651/article/details/112237507
最近讓我寫一篇NETCONF在網絡運維中實際應用的讀者越來越多,趁着最近回沙特后能把KAUST堆滿倉庫的3850, 9200, 9300等IOS-XE真機設備拿出來做實驗,趁這個機會我就寫寫NETCONF,YANG和ncclient,分為上、下兩篇,上篇講NETCONF和YANG,下篇講ncclient,包含理論和實戰。以后有時間也會講講REST和RESTCONF。
NETCONF的前世今生
2002年6月,互聯網架構委員會(Internet Architeture Board,簡稱IAB)舉辦了一個主題為Network Management的workshop,邀請了一大幫研發界業內名氣響當當的巨佬(大多來自IETF)共同商議討論彼時普遍使用的網絡管理協議,找出它們各自的優勢和缺點,並列出一個優秀的網絡管理協議必須具備的特征,准備為開發下一代網絡管理協議(NextGen Network Management Protocol)做准備。2003年5月,IETF發布了RFC 3535(Overview of the 2002 IAB Network Management Workshop),正式提出了下一代網絡管理協議應該具備的七大特征:

在這個背景下,IETF於2006年12月率先發布了RFC 4741, 也就是NETCONF這個基於XML,用來替代CLI、SNMP的網絡配置和管理協議。在隨后幾年加加改改進行一番修訂后,IETF又於2011年6月以RFC 6241作為終稿將其再次發布。
雖然NETCONF年齡不算小,但是倒退10年前你要是問一個網絡工程師什么是NETCONF(更別提YANG了),大概率你會看到對方一臉懵逼的把你看着,因為當時主流的思科IOS設備根本就不支持NETCONF,當時的思科對NETCONF並不感冒,而是自己閉門造車分別在2007年和2012年搞出了WSMA(Web Service Management Agent)和onePK這兩個API。那些年跟隨思科的步伐一路從CCNA,CCNP,CCIE摸爬滾打起來的網工壓根就沒聽說過還有這么一個書上不會教,考試不會考,工作中也基本用不到的非常小眾的技術。十年河東十年河西,這些年隨着SDN和網絡運維自動化技術的強勢崛起,NETCONF終於在誕生10多年后在傳統計算機網絡這個行業里有了一定的曝光率,跟着RESTCONF和gRPC這倆哥們一起站在時代的風口上飛了起來。
NETCONF理論部分
關於NETCONF的理論部分網上有很多資料,最權威的肯定還是RFC 6241,這里做一下總結:
1. NETCONF的協議框架分為四層:由低到高分別為安全傳輸(Secure Transport),消息(Messages),操作(Operations)和內容(Content):

- 安全傳輸層最常見、最常用的是SSH,這也是NETCONF和同為最近幾年炒的火熱的REST(基於WEB)最大的區別
- 消息層基於Remote Procedure Call(遠程調用)這個協議,其作用是提供一個簡易的不依賴於傳輸層,生成RPC和通知消息框架的通信協議。在后面的NETCONF實驗中你會多次看到這兩個東西。
- 操作層定義了一組用來配置、復制、刪除設備命令以及獲取設備信息的基本操作,基本操作包括get, get-config, edit-config, copy-config, delete-config, lock, unlock, close-session, kill-session,這些基本操作都是在XML語言下被調用,比如等等,后面實驗部分會講到。
- 內容層由管理數據內容的數據模型定義,該數據模型也就是我們后面會講到的YANG。
2. NETCONF的編碼格式基於XML,基於XML來做網絡管理主要是看中了XML強大的數據表示能力(對初學者來說XML其實並不怎么友好,不如JSON, YAML那么易讀和容易上手,這是我個人的觀點)。
3. NETCONF網絡架構由客戶端和服務器組成,客戶端就是我們的主機,服務器就是被操控的交換機或者路由器,NETCONF默認使用端口830,可以更改。
4. NETCONF協議中還有一個重要的概念叫做數據集(Datastores),數據集的作用是用來存儲一份配置數據的備份,確保設備能從開機時的初始狀態進入到它能正常運行時的工作狀態(說白了就是改了配置后需要write memroy,不然重啟設備后配置會丟失)。數據集分為Running(類似於思科的running config), Start-up(類似於思科的startup config)和Candidate(思科IOS-XR會用到)三種,其中只有Running這個datastore是強制使用的。
講完NETCONF的理論部分,下面再來看看YANG。
什么是數據模型?
在講YANG之前,我們首先需要知道什么是數據模型。
數據模型的作用是用來描述一組具有統一標准的數據,並用明確的參數和模型來將數據的呈現標准化、規范化。舉個例子,不同廠商之間對一些行業術語的規范及具體參數存在較大差異,比如用來區分路由協議優先級,在思科這邊被稱作管理距離(Administrative Distance)的東西到了Juniper那邊被改叫做Route Preference,並且它們分配給各個路由協議的AD和RP值也不一樣,比如RIP在思科的AD為120,在Juniper的RP為100, 又比如OSPF在思科的AD為110,而在Juniper這邊OSPF還被分為OSPF Interal(RP值為10),OSPF External(RP值為150)。雖然不同廠商之間對某些技術標准存在這樣那樣的差異,但是對於絕大部分技術它們還是遵守統一標准的,比如VLAN。
用來描述VLAN的數據無外乎如下幾點:
1. VLAN ID (1-4096的整數,rw類型)
2. VLAN Name (用字符串代表的VLAN名稱,rw類型)
3. VLAN State (用枚舉表示的down/up或shutdown/no shutdown表示的VLAN狀態,ro類型)
可以看到類似於這種明確定義了數據內容及其數據類型和范圍,以及rw、ro類型的一套模型,就被叫做數據模型。
YANG
YANG是一種“以網絡為中心的數據模型語言”(Network-centric data modeling language),由IETF於2010年10月(也就是NETCONF終稿發布之前的一年)在RFC 6020中被提出,其誕生之初的目的很明確, 是專門為NETCONF量身打造的建模語言,不過現在也被REST和其他協議所采用。
YANG模型(Model)
YANG的模型分為標准(Open或者Standard)和私有(Native)兩種類型,其中標准類型中比較著名的有IETF, IEEE, OpenConfig等國際知名組織制定的模型(IETF制定的YANG模型最常見)。除標准YANG模型之外,各家廠商又根據自家產品的不同設計了私有的YANG模型,比如思科、Juniper、華為、Fujitsu、諾基亞等都有自家的YANG模型。
其中思科的YANG模型又分為Cisco Common和Cisco Platform Specific,其中前者為思科所有OS(IOS-XE, IOS-XR, NX-OS)通用的YANG模型,后者為一些OS上獨占的YANG模型。

YANG模塊(Module)
模塊(Module)是YANG定義的基本單位,一個模塊可以用來定義一個單一的數據類型,也可以增加一個現有的數據模型和其他節點:
下面是一個叫做ietf-interfaces,由IETF制定,用來描述設備端口參數的YANG模塊:

在Github下載YANG模塊
在Github(https://github.com/YangModels/yang)上存放着大部分標准(standard)和私有(vendor)的YANG模型,截止2020年9月,標准模型中包含IETF,IEEE,ETSI等國際知名組織和協會制定的YANG模塊,私有模型中包含思科,Juniper,華為,諾基亞,富士通在內的廠商自己制定的YANG模塊。

我們可以通過git clone來下載上述所有標准和私有的YANG模型及其對應的模塊:
git clone https://github.com/YangModels/yang.git

下載完畢后,當前目錄下多出來了一個名叫yang的子目錄,其中yang/standard/ietf/RFC下包含了全部由IETF制定的YANG模塊,其中也包含我們上面舉例的ietf-interfaces模塊(不在截圖里)。

用cat ietf-interfaces.yang查看該模塊的內容:

你也許會問,怎么和上面我們舉例的ietf-interfaces模塊內容不一樣?這是因為上面的例子中我們是以樹形格式(Tree View Format)展開ietf-interfaces模塊,而這里用cat查看的是該模塊的源代碼。我們可以用pyang這個Python模塊來以樹形格式的形式查看一個YANG模塊的具體結構。
Pyang
Pyang是Python專為YANG開發的一個開源模塊,主要有三個功能:1. 用來驗證YANG模塊代碼的准確性,2. 將YANG模塊轉換成其他格式(比如我們前面講到的樹形格式), 3. 從YANG模塊中生成代碼。這里我們主要講下如何使用Pyang來將剛才的ietf-interfaces.yang這個模塊轉化為樹形格式。
首先通過pip下載安裝pyang:

然后回到yang/standard/ietf/RFC下,使用命令pyang -f tree ietf-interfaces.yang即能將ietf-interfaces這個YANG模塊轉換成樹形模式查看。

實驗環節
講完理論后來做實驗。實驗環境很簡單,就是一台CENTOS 7主機和一台思科3850的交換機直連。
實驗拓撲

主機操作系統:CentOS 7
交換機型號:WS-C3850-48P-S
交換機OS版本:IOS-XE 16.09.05 (Fuji)
主機IP: 172.16.224.27
交換機IP: 172.16.224.28
實驗設計的端口為交換機的GigabitEthernet1/0/33,其初始配置如下:

開始實驗前先提幾點使用NETCONF的重點:
- IOS-XE版本必須為16.3以上。
- Netconf默認使用TCP端口830, 可以更改。
- Netconf的傳輸協議基於SSH,在交換機上必須開啟SSH, 並且用戶特權級別必須為15。
- 如果交換機配置了AAA+TACACS(比如說思科的ISE),必須保證配置了“aaa authorization exec default local”,然后使用交換機本地創建的用戶名(非ISE上的用戶名),否則在主機端會出現“Permission denied, please try again.”,在交換機端會出現“%DMI-5-AUTHENTICATION_FAILED:”的錯誤:


實驗步驟:
- 首先在交換機上開啟NETCONF,方法很簡單,在全局模式下輸入netconf-yang和netconfg ssh(可選,前面理論部分已經講了,NETCONF默認使用的是SSH作為安全傳輸層協議,所以netconf ssh這條命令默認就是開啟的,不需要特意配置)即可。其余的交換機初始配置,比如開啟SSH和創建特權級別為15的用戶請讀者自行完成,這里就不講了。
SW(config)#netconf-yang SW(config)#netconf ssh (默認是開啟的)
2. 回到主機,通過SSH訪問交換機的830端口:

3. 連接成功后,交換機會回復一個hello包,以及一長串capabilities,也就是該交換機支持的yang model:既有思科的,也有IETF的,由於回顯內容過多,下圖只截取部分以作演示:

4. 隨后我們復制粘貼下列XML代碼向交換機回復一個hello包(交換機不會做出任何回應),之后主機和交換機之間的netconf session即建立成功。
<?xml version="1.0" encoding="UTF-8"?>urn:ietf:params:netconf:base:1.0]]>]]>

這里簡單講下XML語言的格式和內容,XML指令以<?xml version="1.0" encoding="UTF-8"?>開頭,其中:
- :表示一條XML指令的開始。
- xml:表示此文件是XML文件。
- version:NETCONF協議版本號。
- encoding:字符集編碼格式,當前僅支持UTF-8編碼。
- ?>:表示一條XML指令的結束。
里:
- hello表示主機(NETCONF客戶端)向交換機(NETCONF服務器)回復的hello包。
- xmlns是XML Namespace(XML命名空間)的縮寫,在XML里面,元素名稱(你可以把它理解為Python中的變量名)是由開發者自己定義的,當將兩個不同的文檔合並成一個文檔,如果兩個文檔里面使用相同的元素名時,就會發生命名沖突。比如說你和我分別開發了一個XML文檔,我用name作為元素名稱來描述一個人名,而你也用name作為元素名稱來描述一個地名,雖然我倆描述的東西不一樣,但是你我定義的元素名稱(name)是一樣的,當我倆的文檔被合並成一個文檔時,就會造成沖突,而XML命名空間的作用就是避免XML內元素的沖突。
- urn:ietf:params:xml:ns:netconf:base:1.0, 在RFC 4741中規定了所有涉及NETCONF協議的元素必須以urn:ietf:params:xml:ns:netconf:base:1.0作為XML命名空間。
- 代表能力集,代表具體的能力,是NETCONF客戶端和服務器互相向對方說明自己具備什么能力的作用,這里的urn:ietf:params:netconf:base:1.0表示客戶端告訴服務器:我具備使用IETF制定的NETCONF協議的能力。
- 和Python不一樣,XML並沒有嚴格要求縮進,但是為了美觀和可讀性,一般我們用兩個空格或者四個空格做縮進。
- 注意代碼最尾部的]]>]]>,它是NETCONF客戶端和NETCONF服務器用來表示消息請求或回復終止的部分(用來告知對方“我話說完了,輪到你了”),並不是XML語言本身的一部分,后面會說明為什么它很重要。
5. 發送下列XML代碼向交換機查詢Gi1/0/33端口的配置:
<?xml version="1.0" encoding="UTF-8"??>1/0/33]]>]]>
隨即交換機會回復一個rpc-reply包(下圖紅框中的部分),后面的內容即我們請求的Gi1/0/33端口的配置信息,包括該端口下的description和IP地址(為空)。

6. 如果你覺得交換機回復的rpc-reply不易讀,可以將它復制粘貼到Code Beautify(https://codebeautify.org/xmlviewer),用Code Beautify下面XML Viewer提供的Tree View或者Beautify / Format讓交換機的rpc-reply內容更易讀。


注意復制RPC-REPLY內容時不要把末尾的]]>]]>給一並復制了(前面講了它們不是XML語言的一部分),不然Code Beautify會報錯:


7. 接下來我們用下面這段XML代碼來查詢交換機的running configuration。請自行嘗試這里就不放截圖了:
這里我故意沒做縮進,就是為了告訴你XML沒有嚴格要求代碼縮進。
<?xml version="1.0"?>]]>]]>
8. 用下面這段XML代碼來為端口Gi1/0/33添加一個description,內容為test XML,表示該description是我們通過NETCONF配置的:
<?xml version="1.0"? encoding="UTF-8"??>1/0/33test XML]]>]]>
這里我們使用到了這個前文NETCONF理論部分講到的基本操作,通常下面會接一個,表示需要修改配置的目標,表示數據集,這里我們要更改的是startup這個數據集(也可以使用running/),后面的表示這里我們使用了前面講到了的思科私有(Native)YANG模型。
回到交換機上驗證Gi1/0/33的配置:

9. 最后我們用下面這段XML代碼給Gi1/0/33配置一個10.1.1.2 /24這個IP地址
<?xml version="1.0"? encoding="UTF-8"??>1/0/33 10.1.1.2 255.255.255.0]]>]]>
之后回到交換機上驗證Gi1/0/33的配置:

關於NETCONF和YANG的理論和實戰就講到這里,可以看到NETCONF這種通過復制粘貼XML代碼的操作方式對傳統工程師來說很不適應,雖然不太好用,但NETCONF確實是SDN時代網工們必須掌握的技能之一。下篇我將繼續講解ncclient這個Python專為NETCONF客戶端開發的第三方模塊,看看NETCONF結合Python會不會省事一些。