天天看點

Netconf配置及其RPC和Notification下發流程解析 一、Netconf編譯與配置二、RPC和Notification下發流程解析 三、總結

Netconf配置及其RPC和Notification下發流程解析

最近兩個月一直在搗鼓netconf,現在搞得小有成效,是以總結一番,以便和廣大網友進行深入探讨。

我們是基于libnetconf開源軟體(https://github.com/CESNET/libnetconf)進行二次開發。對于這套代碼,給我感覺的就是一個“亂”。相比于一些成熟軟體來說,這個軟體還有很多地方需要改善,比如說代碼中經常出現魔鬼數字、某些函數長度接近1000行(source insght都無法解析)。好在,這個軟體一直在更新維護中,還是非常感謝這群無私的人。

在github中有兩套libnetconf, 一套是libnetconf,另外一套是libnetconf2。libnetconf2是正在開發中的版本,還未正式釋出。這個版本相比于libnetconf會有很大變化,比如說:libnetconf中編譯yang模型是采用外部軟體pyang進行,而到了libnetconf2中會把編譯工具會內建到libnetconf2中。從個人角度來說,還是期待libnetconf2。

一、Netconf編譯與配置

1.1 編譯

移植軟體的第一步就是編譯,如果是交叉編譯的話,那份痛苦是不言而喻的。對于我們項目來說,需要移植到powerpc平台上,是以很多庫都需要自己編譯出來(編譯libnetconf花了一天半)。這裡把一些必需依賴庫編譯方法以及編譯過程中遇到的錯誤,展示出來,免得大家多走彎路。

Linux編譯三步驟:configure,make,make install。如果不熟悉linux編譯的請自學。

1.2 設定環境變量

為了編譯友善,設定一下環境變量(其實也可不設定)即設定工具鍊所在位置,具體設定如下:

Netconf配置及其RPC和Notification下發流程解析 一、Netconf編譯與配置二、RPC和Notification下發流程解析 三、總結

将這兩個目錄設定到PATH中,避免不必要的錯誤:

Netconf配置及其RPC和Notification下發流程解析 一、Netconf編譯與配置二、RPC和Notification下發流程解析 三、總結

1.3 編譯依賴庫

由于依賴庫非常多并且不同的編譯環境,編譯情況也不盡相同,這裡隻把常見依賴庫和編譯有困難的庫,給大家展示出來。

1、libxml2編譯

1)configure 建立makefile

Netconf配置及其RPC和Notification下發流程解析 一、Netconf編譯與配置二、RPC和Notification下發流程解析 三、總結

2)make 編譯 最後單元測試編譯失敗,對于我們使用者來說沒有影響,因為庫檔案已經生成。

3)make install 安裝到指定目錄中,在上面configure過程中已經設定為目前目錄下build_install。 将編譯生成的lib和include這兩個目錄,拷貝到工具鍊中。

Netconf配置及其RPC和Notification下發流程解析 一、Netconf編譯與配置二、RPC和Notification下發流程解析 三、總結

2、libssh編譯

在編譯libssh的時候需要編譯libz、openssl依賴庫,這兩個比較容易編譯出來,是以不再闡述。Libssh采用cmake方式編譯:

1)修改DefineOptions.cmake檔案,打開靜态庫編譯選項,如果不需要靜态庫則可以忽律此步驟

Netconf配置及其RPC和Notification下發流程解析 一、Netconf編譯與配置二、RPC和Notification下發流程解析 三、總結

2)建立mkdir build_install儲存編譯生成的檔案,進入此目錄執行cmake指令,此步驟實則是生成makefile過程,如下圖所示:

Netconf配置及其RPC和Notification下發流程解析 一、Netconf編譯與配置二、RPC和Notification下發流程解析 三、總結

進入該目錄中,然後輸入cmake .. (此處有兩點,即上層目錄)

3)執行make操作,進行編譯,編譯完後如下圖所示:

Netconf配置及其RPC和Notification下發流程解析 一、Netconf編譯與配置二、RPC和Notification下發流程解析 三、總結

4)将include、靜态庫和動态庫拷貝到工具鍊中即可。

常見兩種編譯方式都已介紹,後面在編譯其他依賴庫,基本上都是一樣的套路。

3、編譯libgpg-error

1)這個編譯沒有任何問題,我們需要把編譯生成的可執行檔案如gpg-error、gpg-error-cofig拷貝到工具鍊中,并且以powerpc-603-linux-gun-進行重命名。

2)拷貝頭檔案和庫到對應的工具鍊中。

4、編譯libgcrgpt

編譯libgcrgpt時候,如果連接配接過程中出現錯誤,比如說找不到某個函數,原因是在編譯過程進行了優化,将原始函數定義修改為以下劃線開始。此問題修改是configure過程中,增加一個參數:—disabled-asm。

5、編譯libnetconf

将上面一些依賴庫和其他庫都編譯完後,再編譯libnetconf就非常容易了。

1) ./configure --host=powerpc-603-linux-gnu --build=i686-pc-linux-gnu --prefix=

pwd

/build_install

2)make

3)make install

這三步非常的順利沒有出現任何錯誤。

6、編譯netopeer

Netopeer是libnetconf官方提供server,cli以及編譯工具lnctool。在編譯netopeer時候遇到了無法解析yang檔案問題,此處解決的方法,更新python并安裝pyang。

1.4 工具lnctool

假設經過第一步後成功編譯出libnetconf和netopeer,這樣我們就可以直接運作netopeer。netconf預設監聽端口是830端口。

衆所周知,netconf協定支援自定義rpc,是以此步驟需要做的是如何在現有netconf中增加自己的yang模型以及執行自己的rpc??這裡就需要用到這個工lnctool。這個工具是用python實作的,裡面代碼也比較簡單,比如說調用其他應用程式(pyang)或者直接寫檔案。

這裡有一個官方提供的demo(圖靈機),位址為:https://rawgit.com/CESNET/libnetconf/master/doc/doxygen/html/d9/d25/transapi.html#transapiTutorial

這個文檔有兩個重點,第一個重點是生成yin檔案以及源碼.c檔案:

Netconf配置及其RPC和Notification下發流程解析 一、Netconf編譯與配置二、RPC和Notification下發流程解析 三、總結

另外一個重點是就是實作源檔案中相關接口—rpc函數。當經過以上兩個步驟之後,就可以進行編譯,預設編譯出動态庫.so檔案。

當我們把rpc函數實作之後,就可以通過另外一個工具,netopeer-manager安裝自定義模型,使用指令行如下:

Java

1 netopeer - manager add -- name [ module name ]    -- model    [ model path ]    -- transapi    [ model share library ]    -- datastore [ module datastore file ]

如下圖所示,當然我們也可以不使用netopeer-manager,直接修改配置檔案,下面章節我将會介紹。

Netconf配置及其RPC和Notification下發流程解析 一、Netconf編譯與配置二、RPC和Notification下發流程解析 三、總結

1.5 修改配置檔案

【libnetconf之Streams】

衆所周知,netconf之前rpc、notification兩種操作,其中notification類似server主動發送消息,然而它不是簡單的主動發送,而是支援訂閱操作。Libnetconf就是通過stream實作notification(stream其實就是一個普通檔案)。

Streams預設存放路徑/var/lib/libnetconf/streams。這個目錄中一般有兩個配置檔案,NETCONF.event:這個檔案事件接收者,也就是stream對象。業務層隻需要把事件寫入到這個檔案中,那麼所有的訂閱者就能夠都接收到這個事件。這個檔案在後面notification篇會詳細介紹。

NETCONF.rules:這個檔案目前總是空的。

【netopeer配置檔案】

Netopeer是官方釋出的一個服務端,但從個人角度認為這個server寫的不是很好,有些内容很淩亂。如果有時間日後會重寫這個server。

Netopeer預設安裝路徑是/usr/local/etc/netopeer或者/etc/netopeer/,在這個目錄中有兩個子目錄分别為cfgnetopeer,modules.conf.d。

1、cfgnetopeer

這個目錄是netopeer相關配置,檔案雖然很多,但是我們隻需要關注datastore.xml檔案即可。datastore.xml主要包含三部分(三個datastore):

Netconf配置及其RPC和Notification下發流程解析 一、Netconf編譯與配置二、RPC和Notification下發流程解析 三、總結

說一下備選配置:備選配置是即将生效的配置,換句話說,使用者下發的配置一般都會儲存在備選配置中,等待時機(等待commit消息),将備選配置儲存到running中。注:netopeer中實作的datastore是最簡單的方式,以檔案方式存儲配置。對于這種方式,性能是最低的,對于一些性能要求較高的項目,請考慮一下這個地方的行問題!!提示:這個地方datastore可以采用資料庫,如使用no-sql型資料庫。

2、modules.conf.d

模型配置儲存的目錄,這個目錄存儲的是模型相關配置。一說到模型就感覺有點抽象,那好我用大白話說一下:這個目錄儲存的就是yang檔案定義的module,這次夠直白了吧!!!

Netconf配置及其RPC和Notification下發流程解析 一、Netconf編譯與配置二、RPC和Notification下發流程解析 三、總結

依賴模型:為了實作主模型,往往需要其他模型作為輔助。依賴模型在yang檔案中的展現是通過import關鍵字導入的。

主模型:yang檔案中定義的module就是主模型。依賴模型可以有多個,但是主模型隻能有一個。

Datastore:用于存儲配置,可以是檔案,也可以其他任何存儲媒體。如果在datastore是一個檔案,那麼不用手動建立,netopeer在啟動的時候會建立的。

小結:在上面講過使用netopeer-manager添加新增模型,就是修改或者建立上面配置檔案。是以我們完全可以不使用netopeer-manager這個工具。

二、RPC和Notification下發流程解析

Libnetconf代碼自己隻把rpc、notification流程詳細看過,像一些netconf-session維護,hello消息等沒有仔細看。像之前我說過的,libnetconf有些代碼非常長且source insight無法寫解析出來,是以有些代碼片段可能比較突兀,請諒解。

2.1 總體流程圖

Netconf配置及其RPC和Notification下發流程解析 一、Netconf編譯與配置二、RPC和Notification下發流程解析 三、總結

圖1:總體流程圖

上圖是隻是最簡易流程圖,但已經能夠描述清楚。如果有人比較清楚netconf協定,會有一些疑問,為什麼上圖中沒有包含hello流程??難道是在Others裡面嗎??其實不是,在進入這個流程之前,hello消息已經處理過了,也就是說進入這個流程時netconf-session已經建立成功(create_netconf_session處理)。

消息分類:

  • 消息close-session:優雅終止netconf-session。
  • 消息kill-session:強制終止netconf-session并且釋放相關資源。
  • 消息 create-subscription:訂閱消息,此消息會在下一篇notification中介紹的。

前兩種消息類似,都可以達到終止會話功能,具體差别可以先閱讀以下netconf相關協定以及netopeer中代碼。我們分析的重點在othes消息中。

2.2 rpc處理流程

下面流程圖是ncds_apply_rpc2call函數處理流程。

Netconf配置及其RPC和Notification下發流程解析 一、Netconf編譯與配置二、RPC和Notification下發流程解析 三、總結

圖2:rpc處理流程圖

注:這個函數代碼行數非常多,source insight無法正常解析。在這裡我會分析兩個分支流程,一個edit-config,一個unkown。 這兩個有什麼差別呢??edit-config是協定标準規定的rpc,而unkown是自定義rpc處理。由于各個廠商需求不同,可能有的廠商定義并實作了自定義rpc,有的廠商可能就沒有自定義,但自定義rpc完全可以不出現。

1、edit-config配置流程

Netconf配置及其RPC和Notification下發流程解析 一、Netconf編譯與配置二、RPC和Notification下發流程解析 三、總結

圖3:代碼片段1

開始的幾行代碼,是從rpc結構中擷取相應參數,這個沒有什麼可解釋的。

下面的if判斷是對edit-config表現形式區分的。Edit-config有兩種表現形式,常見表現形式是所有配置項都在edit-config中展現,這種也是标準edit-config,如圖4:

Netconf配置及其RPC和Notification下發流程解析 一、Netconf編譯與配置二、RPC和Notification下發流程解析 三、總結

圖4:标準edit-config格式

另外一種edit-config是以url表現的,這種表現形式在協定中也沒有樣例,具體是什麼樣子,我也不太清楚。

這裡分析一下edit-config處理流程,代碼如下:

Java

1 ret = ds -> func . editconfig ( ds , session , rpc , target_ds , config , nc_rpc_get_defop ( rpc ) , nc_rpc_get_erropt ( rpc ) , & e ) ;

這裡是一個回調函數,如果datastore的表現形式是file,則此處的回調函數是:ncds_file_editconfig。對于這個函數,開始一部分是進行正常校驗,函數處理流程圖如下:

Netconf配置及其RPC和Notification下發流程解析 一、Netconf編譯與配置二、RPC和Notification下發流程解析 三、總結

補充說明一下:

1)file_rollback_store是為了復原,裡面機制是備份目前datastore全部配置。如果出現錯誤,并且在下發rpc的時候,下發了rollback-on-error标志,才會進行復原。

2)compact_edit_operations 主要根據下發内容進行合并處理。

3) edit_operations 下發rpc的時候往往下發操作類型,如果沒有下發,預設是replace。操作類型一共有replace,create,delete,remove,merge五種。根據操作類型不同,修改對應的datastore。

2、自定義rpc處理流程

對于自定義的rpc來說,比較簡單。在上面也說過了,自定義rpc處理流程是Unkown分支中進行處理,具體代碼如下:

Netconf配置及其RPC和Notification下發流程解析 一、Netconf編譯與配置二、RPC和Notification下發流程解析 三、總結

這個回調函數實作在什麼地方呢??其實就在我們編譯yang模型時候生成的.c檔案中。這個地方需要注意:回調函數中必須傳回rpc_reply消息,否則libnetconf會自己構造一個rpc_error消息傳回給用戶端。

上面是rpc整個流程,代碼分析不多,大部分都是流程圖,其實隻需要把流程搞通,至于代碼熟悉度,隻是時間問題。上面分析的隻是rpc消息中edit-config消息,其他消息比較簡單,需要自己去看一下。下面分析一下notification消息。

2.3 notification處理流程

在介紹notification之前,先普及一下netconf協定一點點基礎知識。

1)若想實作notification通知消息,用戶端必須下發rpc訂閱消息即create-subscription

2)在下發訂閱消息時候如果參數中沒有stream則預設stream是NETCONF。個人了解stream是隧道、通道含義。使用者可以訂閱某個隧道下面某些事件。事件上報時,流經哪個隧道,這完全取決于業務子產品。

3)Netconf協定規定,一個netconf-session有且隻有一個訂閱,并且訂閱消息一旦建立就不允許修改。

4)訂閱消息支援結束時間stopTime參數,如果沒有此參數則訂閱功能與netconf-session是具有相同的生命周期。

Netopeer-server中實作rpc訂閱消息代碼如下,代碼比較簡單,就是建立一個線程監聽stream對象。

Netconf配置及其RPC和Notification下發流程解析 一、Netconf編譯與配置二、RPC和Notification下發流程解析 三、總結

輪詢具體實作函數是ncntf_dispatch_send,這個函數是一個死循環。但是從命名上來看,感覺不像死循環(是以我吐槽libnetconf代碼不友好)。下面ncntf_dispatch_send函數具體處理流程:

Netconf配置及其RPC和Notification下發流程解析 一、Netconf編譯與配置二、RPC和Notification下發流程解析 三、總結

建立notification事件,可以有以下接口,

事件是xml節點方式作為入參:

Java

1 2 int ncxmlntf_event_new ( time_t etime , NCNTF_EVENT event , . . . ) ; nc_ntf * ncxmlntf_notif_create ( time_t event_time , const xmlNodePtr content ) ;

事件是以字元串方式作為入參:

Java

1 2 int ncntf_event_new ( time_t etime , NCNTF_EVENT event , . . . ) ; nc_ntf * ncntf_notif_create ( time_t event_time , const char * content ) ;

以上接口使用方式可參考頭檔案說明。

三、總結

如果沒有任何Netconf基礎就看這篇文章,是毫無意義的,是以在看之前請先熟悉一下netconf協定。

libnetconf源碼還是比較年輕的代碼,裡面有很多需要優化地方,例如:源碼中有很多頻繁的申請、釋放記憶體,這樣很容易造成記憶體碎片,還有在實作notification時采用文本檔案方式實作stream,這樣的性能是低下的。

雖然libnetconf中有很多不足,但是它還是做了很多事情,如果沒有精力開發一套netconf協定棧,那麼大家可就湊合用吧!!

至此,netconf分析基本結束,歡迎大家一起讨論!!

作者簡介:

徐小冰:畢業于河北大學,主要從事嵌入式軟體開發,虛拟化,SDN。目前基于ODL和Open vSwitch進行二次開發,希望與廣大網友一起探讨學習。作者系OpenDaylihgt群(194240432)資深活躍使用者,@IT難人

--------------華麗的分割線------------------

本文系《SDNLAB原創文章獎勵計劃》投稿文章,該計劃旨在鼓勵廣大從業人員在SDN/NFV/Cloud網絡領域創新技術、開源項目、産業動态等方面進行經驗和成果的文字傳播、分享、交流。有意向投稿的同學請通過官方唯一指定投稿通道進行文章投遞,投稿細則請參考《SDNLAB原創文章獎勵計劃》