《Cisco IOS XR技術精要》一2.1 Cisco IOS XR內核
本節書摘來自異步社區《Cisco IOS XR技術精要》一書中的第2章,第2.1節,作者 【美】Mobeen Tahir , Mark Ghattas , Dawit Birhanu , Syed Natif Nawaz,更多章節內容可以訪問雲棲社區“異步社區”公眾號查看
2.1 Cisco IOS XR內核
Cisco IOS XR技術精要
Cisco IOS XR是一款基於微內核、高度分布的操作係統。Cisco IOS XR中使用的微內核是一種由QNX Software Systems公司開發的QNX Neutrino實時操作係統(RTOS),其使用的內核是輕量級的,僅提供了少量必要的服務。該係統負責終端處理、調度、任務交換、內存管理、同步、進程間通信等工作。微內核係統不包括如設備驅動器、文件係統和網絡棧之類的係統服務;這些服務是通過內核外的獨立進程來執行的,可以像其他應用那樣重新啟動。
微內核是一種兼容POSIX(可移植操作係統接口)的內核。POSIX定義了兼容POSIX的OS必須遵循的OS規範和針對API和OS服務的測試組。基於POSIX兼容的內核開發的應用和服務可以方便地移植到另一個兼容POSIX的內核上。
基於微內核的OS必要的一點就是模塊性。微內核提供了極具高度的模塊性。OS是由一組通過微內核來管理、通過消息傳送服務相結合的協作進程來執行工作的。每種進程運行在各自的地址空間中,不會因其他進程而造成內存數據損壞。微內核架構中有一個重要的因素就是快速內容交換能力,該能力提高了模塊性的靈活程度。因為內容交換使用的CPU開銷很低,它可以使每種應用和服務最大化地使用各自的進程並運行在各自的地址空間中。例如,Cisco IOS XR中,BGP、OSPF、OSPFv3、RIBv4、RIBv6等應用會執行在不同的進程中。而且,如果路由器上配置了多個OSPF進程,那麼係統會將每個進程分配進與其他進程完全分離的單獨進程實例中。這種快速內容交換能力使更優的模塊性成為可能,這裏的快速內容交換能力是指由QNX提供、Cisco加強的微內核和有效進程間通信的快速能容交換能力。進程間通信內容將在本章後續小節中做更詳細的介紹。
2.1.1 線程
如圖2-1所示,OS是由一組通過微內核管理的協同進程組成的。微內核提供了線程調度、搶占,以及到進程的同步服務。微內核還扮演著消息傳送“通道”的角色。微內核和進程管理器共同構成了procnto進程。每種進程運行在單獨的地址空間中,並且重啟不會影響到其他進程。

在開發一款應用時,經常需要考慮並發地執行多種算法。這種並發性可以通過使用一個進程中的多個線程來實現。線程(thread)是執行與調度操作的最小單元。換句話說,一個進程(process)包含了多個相關線程,並且定義了線程可以執行的地址空間。每個進程至少帶有一個線程。有關線程將在2.1節中做詳細的介紹。
如讀者所見,在例2-1中的show processed threadname 120命令輸出中,IOS XR的BGP進程具有多個線程,每個線程各負其職,包括輸入、輸出、導入等。在下例的輸出中,120表示BGP進程的作業ID,作業ID(JID)是分配給每個進程的唯一編號,更多內容將在2.1節中做更詳細的介紹。
例2-1 BGP進程的線程名稱

圖2-2給出了最為常見的線程狀態以及各狀態之間的轉換。內側的圓圈實際上代表了兩種截然不同的狀態:ready和running。線程狀態可以從ready轉變成running,反之亦然。處於running狀態的線程同樣可以轉變成圖2-2中所示的其他任意一種狀態。
Cisco IOS XR微內核使用一種搶占的、基於優先級的、非自適應的調度算法。每個線程分得一個優先級。調度程序負責基於已分配的優先級選擇下一個執行的線程。處於ready狀態中優先級最高的線程將被將被選擇為running。每個優先級級別都會有一個ready狀態的先進先出(FIFO)隊列。
空閑線程是procnto進程中的一種特殊線程,因為隻有這種線程的優先級為0並使用FIFO調度機製。而且,空閑線程隻會處於running或ready狀態,並且永遠不會主動地交出CPU控製權。不過,由於其使用的優先級最低,所以空閑進程可以被任何處於ready狀態的其他進程所搶占。
running狀態的線程可能由於係統唿叫(如內核唿叫、異常或硬件中斷)、被阻斷、被搶占,或主動交讓操作而轉變成某種不同的狀態。如果running狀態的線程被更高優先級的線程搶占了,將會被放入同優先級ready隊列的最前端。另一種情況,如果是由於線程的時隙用盡或是主動交讓進程的原因,將會被放入同優先級ready隊列的最末端。時隙(timeslice)指的是當同一優先級的ready隊列中,如果一個或多個線程為running狀態時,每個running狀態的線程可以執行的最大時間長度。
當線程需要等待某個事件的發生時(如回複消息),running線程會被阻斷。被阻斷的線程將會永久地進入對應的阻斷狀態,直到阻斷消失。當進程的阻斷結束後,線程通常都會被放入同優先級ready隊列的最末端。當然也有一些例外。

例如,如果一個服務器線程正在等待一個客戶端請求,將會進入阻斷(block)狀態。假設受阻斷的服務器線程的優先級為10,而非阻斷的客戶端線程的以優先級20發送請求並等待回應。在這種情況下,服務器線程將會解除阻斷,並將客戶端線程轉變為阻斷的reply狀態。如果服務器線程以10的優先級放入ready隊列,不過還有多個ready狀態的線程優先級為15,這樣的話,即便是客戶端線程的優先級為20,也會影響到客戶端的相應時間。這個問題被稱作優先級倒置。為了防止優先級倒置,微內核使用了優先級繼承機製,可以使服務器線程的優先級臨時地增加成匹配客戶端線程的值(20),並將服務器線程放入客戶端優先級(20)使用的ready隊列中。
2.1.2 調度算法
微內核中提供了如下3種調度算法來滿足不同場景的需要。
FIFO調度。
輪詢調度。
偶發調度。
在FIFO調度中,除非線程主動交讓控製權或被更高優先級線程搶占,否則線程會一直工作下去。在Cisco IOS XR中,隻有procnto進程(內核)中的空閑線程使用FIFO調度算法。
IOS XR中的大多數其他進程都使用輪詢(round-robin)調度,這種調度方法限定了每個線程得到資源控製權的最大時間長度(時隙)。使用輪詢調度的線程會一直運行,直到其主動交讓控製權、被更高優先級線程搶占,或待其時隙用盡。
偶發(sporadic)調度算法允許線程的優先級在下降為低優先級之前,在補充間隔(replenishment interval)內使用常規優先級運行一段時長(預算時間,budget time)。圖2-3說明了偶發調度算法是如何工作的。

假設從t=0ms開始,線程T1和T2準備就緒,其他所有線程處於阻斷狀態。此外,假設T1為偶發調度線程,其常規優先級為30,低優先級為10,預算時間為20ms,補充時間為50ms。T2為輪詢調度線程,優先級為20。實例如下。
1.由於T1的優先級比T2高,所以T1在t=0ms時被優先調度得到服務。
2. 在t=5ms時,帶有40優先級的線程T3阻斷結束,並變為ready狀態。
3. 由於T3帶有比T1還高的優先級,所以T3搶占T1得到服務。搶占的結果是,T1進入優先級30的ready隊列的最前端。
4.在t=10ms時,T3線程被阻斷並交還CPU控製權。此時優先級為30的T1線程和優先級為20的T2線程均處於ready狀態。因此,較高優先級的T1在t=10ms時得到服務。
5. 當t=25ms時,T1線程的預算時間已經用完,由於偶發調度的機製,其優先級被降低成10。此時的T2線程處於ready狀態並帶有20的優先級,所以,T2搶占了T1,從25ms開始得到服務。
6.在t=50ms時,補充間隔的50ms到期,T1線程的優先級恢複成了常規優先級30,於是,又從T2線程上將控製權搶占了回來。
7.當t=70ms時,新補充間隔中的預算時間20ms又被用完,優先級再次降為10,T2再次搶占T1得到服務。
例2-2給出了show process pidin命令的部分輸出。輸出中列出了線程,以及相應的進程ID(pid)、線程ID(tid)、進程名稱、優先級、調度算法和進程狀態。“prio”一列給出了線程的優先級和調度算法。在線程調度符號中,f表示FIFO,r表示輪詢,?表示偶發調度。例2-2中,共有兩個線程使用FIFO調度;procnto線程1和2,這兩個都是內核的空閑線程。每個CPU都會有一個空閑進程。由於此命令是在CRS-16/S的RP上執行的,該RP上共有兩塊CPU處理器,所以顯示出了兩個空閑線程,每個CPU一個。例2-2中還顯示了eth_server進程中的線程3、4、7使用了偶發調度,所有其他線程使用的是輪詢調度。
例2-2 show processes pidin命令輸出

2.1.3 同步服務
微內核提供了一種基於消息傳送的IPC同步機製。這種消息傳送服務可以不經過任何中間組件,直接從發送線程的地址空間中將消息拷貝給接收線程。消息的內容和格式對內核來說是透明的。IPC內容將在2.3節中做更詳細的介紹。
微內核除了提供了消息傳送IPC機製之外,還可以開發出其他使用共享內存空間的IPC機製。不過,訪問共享內存空間必須要求同步來確保數據的一致性。例如,如果某個線程正試圖訪問連接列表,而另一線程正在對列表進行更新,那麼很可能會導致災難性的結果。為了解決這一問題,微內核加入了mutex、condvar和semaphore同步機製。
相互排外鎖,即mutex,用於保證在線程之間單獨地訪問共享數據。在線程訪問共享數據之前,應該先獲得(鎖住)mutex。當完成在共享數據上的操作之後,線程會釋放mutex。任意時間上,隻能有一個線程獲得mutex。如果某個線程試圖鎖住已經被其他線程鎖住的mutex,那麼該線程將進入阻斷狀態,直到mutex解鎖並獲得為止。當線程釋放mutex時,具有最高優先級等待獲得mutex的線程將解除阻斷並成為新的mutex擁有者。
如果高優先級的線程試圖鎖住已經被低優先級線程鎖住的mutex,那麼當前擁有mutex的線程的優先級將會增加到同高優先級的阻斷線程一樣的優先級值。這種機製被稱為優先級繼承(priority inheritance),用來解決優先級倒置的問題。優先級繼承與優先級倒置的內容在之前的客戶端/服務器線程交互部分中有過介紹。
條件變量(condvar)用於等待某些條件的執行(例如超時)。線程在滿足特定條件之前一直處於阻斷狀態。condvar通常與mutex按如下方式結合使用:
鎖住mutex;
等待condvar;
執行動作(操作共享數據);
解鎖mutex。
另一種同步機製被稱為信號量(semaphore),線程狀態由semaphore是否為正數來決定。如果semaphore為正數,線程將解除阻斷訪問資源,semaphore值減1。每次post操作會使semaphore值增加1。可以使用semaphore借助信號控製器來喚醒線程。線程通過semaphore發出一個wait操作,表示等待信號。信號控製器通過semaphore執行post操作,喚醒被semaphore阻斷的線程。
像本節先前例2-2中顯示的那樣,命令show process pidin location< r/s/m >可以列出每個線程的狀態。表2-1給出了一份進程可能獲得的狀態列表。

回到例2-2的輸出,可以看到,某些線程正處於reply狀態,這表示客戶端線程正處於阻斷狀態並等待服務器響應。如果進程一直卡在阻斷狀態,很可能是(Client/Server)進程或應用出了問題。不過,並不是路由器上所有的阻斷進程都是有問題的,因為在進程的選擇過程中,阻斷狀態是一種可預期的行為。有些進程卡在阻斷狀態可能會導致應用不做響應。理解生產網絡中路由器的進程行為是很有必要的。
如果想要查看所有阻斷線程,可以使用命令show processes blocked location< r/s/m>,如例2-3所示。建議在數秒內多使用幾次,這樣可以確定某個阻斷進程是由於錯誤被阻斷還是執行常規IPC交換時的正常阻斷。某些進程,如ksh和devc-conaux設計出來即是阻斷狀態。ksh作為客戶端進程與devc-conaux(服務器進程)進行通信。在用戶提供Console服務器上的輸入信息之前,線程會一直處於阻斷狀態。更具體地講,ksh等待Console或auxiliary端口上的輸入信息並向devc-conaux返回係統消息。當devc-conaux回複ksh,進程狀態將從阻斷變為reply。
例2-3 受阻斷進程

最後更新:2017-06-15 09:31:44