openVswitch(OVS)源代碼分析之工作流程(收發數據包)

        前面已經把分析openVswitch源代碼的基礎(openVswitch(OVS)源代碼分析之數據結構)寫得非常清楚了,雖然訪問的人比較少,也因此讓我看到了一個現象:第一篇,openVswitch(OVS)源代碼分析之簡介其實就是介紹了下有關於雲計算現狀和openVswitch的各個組成模塊,還有籠統的介紹了下其工作流程,個人感覺對於學習openVswitch源代碼來說沒有多大含金量。雲計算現狀是根據公司發展得到的個人體會,對學習openVswitch源代碼其實沒什麼幫助;openVswitch各個組成模塊到網上一搜一大堆,更別說什麼含金量了;最後唯一一點還算過的去的就是openVswitch工作流程圖,對從宏觀方面來了解整個openVswitch來說還算是有點幫助的。但整體感覺對於學openVswitch源代碼沒有多少實質性的幫助,可是訪問它的人就比較多。相反,第二篇,openVswitch(OVS)源代碼分析之數據結構分析了整個openVswitch源代碼中涉及到的主要數據結構,這可是花了我不少精力。它也是分析整個源代碼的重要基礎,更或者說可以把它當做分析openVswitch源代碼的字典工具。可是訪問它的人數卻是少的可憐,爲什麼會這樣呢?

        網上有很多blog寫有關於openVswitch的,但是絕大部分只是介紹openVswitch以及怎麼安裝配置它,或者是一些命令的解釋。對於源代碼的分析是非常少的,至少我開始學習openVswitch時在網上搜資料那會是這樣的。因此對於一個開始接觸學習openVswitch源代碼的初學者來說是非常困難的,什麼資料都沒有(當然官網上還是有些資料得,如果你英文夠好,看官網的資料也是個不錯的選擇),只得從頭開始去分析,可是要想想openVswitch是由一個世界級的傑出團隊花幾年的時間設計而成的,如果要從零開始學習分析它,要到猴年馬月。所幸的是我開始學的時候,公司前輩們提供了些學習心得以及結構資料,所以在此我也把自己的學習心得和一些理解和大家分享。如有不正確之處,望大家指正,謝謝!!!

        言歸正傳,基礎已經學習過了,下面來正真分析下openVswitch的工作流程源代碼。

        首先是數據包的接受函數,這是在加載網卡時把網卡綁定到openVswitch端口上(ovs-vsctl add-port br0 eth0),綁定後每當有數據包過來時,都會調用該函數,把數據包傳送給這個函數去處理。而不是像開始那樣(未綁定前)把數據包往內核網絡協議棧中發送,讓內核協議棧去處理。openVswitch中數據包接受函數爲:void ovs_vport_receive(struct vport *vport, struct sk_buff *skb);函數,該函數所在位置爲:datapath/vport.c中。實現如下:

  1. // 數據包接受函數,綁定網卡後,所有數據包都是從這個函數作爲入口傳入到openVswitch中去處理的,
  2. // 可以說這是openVswitch的入口點。參數vport:數據包從哪個端口進來的;參數skb:數據包的地址指針
  3. void ovs_vport_receive(struct vport *vport, struct sk_buff *skb)
  4. {
  5. struct pcpu_tstats *stats; // 其實這個東西一直沒弄明白,大概作用是維護CPU的鎖狀態
  6. stats = this_cpu_ptr(vport->percpu_stats); // 開始獲取到CPU的鎖狀態,這和linux內核中的自旋鎖類似
  7. u64_stats_update_begin(&stats->syncp); // 開始上鎖
  8. stats->rx_packets++; // 統計數據包的個數
  9. stats->rx_bytes += skb->len; // 記錄數據包中數據的大小
  10. u64_stats_update_end(&stats->syncp);// 結束鎖狀態
  11. if (!(vport->ops->flags & VPORT_F_TUN_ID)) // 這是種狀態處理
  12. OVS_CB(skb)->tun_key = NULL;
  13. // 其實呢這個函數中下面這行代碼纔是關鍵,如果不是研究openVswitch而是爲了工作,個人覺得沒必要(估計也不可能)
  14. // 去弄清楚每條代碼的作用。只要知道大概是什麼意思,關鍵代碼有什麼作用,如果要添加自己的代碼時,該往哪個地方添加就可以了。
  15. // 下面這行代碼是處理數據包的函數調用,是整個openVswitch的核心部分,傳入的參數和接受數據包函數是一樣的。
  16. ovs_dp_process_received_packet(vport, skb);
  17. }

        俗話說有接必有還,有進必有出嘛。上面的是數據包進入openVswitch的函數,那一定有其對應的出openVswitch的函數。數據包進入openVswitch後會調用函數ovs_dp_process_received_packet(vport,skb);對數據包進行處理,到後期會分析到,這個函數對數據包進行流表的匹配,然後執行相應的action。其中action動作會操作對數據包進行一些修改,然後再把數據包發送出去,這時就會調用vport.c中的數據包發送函數: ovs_vport_send(struct vport *vport, struct sk_buff *skb);來把數據包發送到端口綁定的網卡設備上去,然後網卡驅動就好把數據包中的數據發送出去。當然也有些action會把數據包直接向上層應用發送。下面來分析下數據包發送函數的實現,函數所在位置爲:datapath/vport.c中。

  1. // 這是數據包發送函數。參數vport:指定由哪個端口發送出去;參數skb:指定把哪個數據包發送出去
  2. int ovs_vport_send(struct vport *vport, struct sk_buff *skb)
  3. {
  4. // 這是我自己加的代碼,爲了過濾掉ARP數據包。這裏額外的插一句,不管在什麼源代碼中添加自己的代碼時
  5. // 都要在代碼開頭處做上自己的標識,因爲這樣不僅便於自己修改和調試、維護,而且也讓其他人便於理解
  6. /*===========yuzhihui:==============*/
  7. if (0x806 == ntohs(skb->protocol)) {
  8. arp_proc_send(vport,skb);// 自定義了一個函數處理了ARP數據包
  9. }
  10. // 在前篇數據結構中講了ops是vport結構中的一些操作函數的函數指針集合結構體
  11. // 所以vport->ops->send()是函數指針來調用函數,把數據包發送出去
  12. int sent = vport->ops->send(vport, skb);
  13. if (likely(sent)) { // 定義了一個判斷宏likely(),如果發送成功執行下面
  14. struct pcpu_tstats *stats; // 下面的這些代碼是不是覺得非常眼熟,沒錯就是接受函數中的那些代碼
  15. stats = this_cpu_ptr(vport->percpu_stats);
  16. u64_stats_update_begin(&stats->syncp);
  17. stats->tx_packets++;
  18. stats->tx_bytes += sent;
  19. u64_stats_update_end(&stats->syncp);
  20. }
  21. return sent; // 返回的sent是已經發送成功的數據長度
  22. }

        這兩個函數就是openVswitch中收發數據包函數了,對這兩個函數沒有完全去分析它的所有代碼,這也不是我的本意,我只是想讓初學者知道這是數據包進入和離開openVswitch的函數。其實知道了這個是非常有用的,因爲不管你是什麼數據包,只要是到該主機的(當然了包括主機內的各種虛擬機及服務器),全部都會經過這兩個函數(對於接受的數據時一定要進過接受函數的,但是發送數據包有時候到不了發送函數的),那麼要對數據包進行怎麼樣的操作那就全看你想要什麼操作了。

        在這兩個函數中對數據包操作舉例:

        數據包接受函數中操作:如果你要阻斷和某個IP主機間的通信(或者對某個IP主機數據包進行特殊處理),那麼你可以在數據進入openVswitch的入口函數(ovs_vport_receive(struct vport *vport, struct sk_buff *skb);)中進行處理,判斷數據包中提取到的IP對比,如果是指定IP則把這個數據包直接銷燬掉(也可以自己定義函數做些特殊操作)。這樣就可以對整個數據進行控制。

        數據包發送函數中操作:就像上面的函數中我自己寫的那些代碼一樣,提取數據包中數據包類型進行判斷,當判斷如果是ARP數據包時,則調用我自定義的 arp_proc_send(vport,skb);函數進行去處理,而不是貿然的直接把它發送出去,因爲你不知道該數據包發送的端口是什麼類型的。如果是公網IP端口,那麼就在自定義函數中直接把這個數據包掐死掉(ARP數據包是在局域網內作用的,就算髮到公網上也會被處理掉的);如果是發送到外層局域網中或者是相連的服務器中,則修改數據包中的目的Mac地址進行洪發;又如果是個ARP請求數據包,則把該數據包修改爲應答包,再原路發送回去,等等情況;這些操作控制都是在發送數據包函數中做的手腳。

        以上就是openVswitch(OVS)工作流程中的數據包收發函數,經過大概的分析和應用舉例說明,我想對於初學者來說應該知道大概在哪個地方添加自己的代碼,實現自己的功能要求了。

        轉載請註明原文出處,原文地址:http://blog.csdn.net/yuzhihui_no1/article/details/39298321

                                                                                                                                    如有不正確之處,望大家指正,謝謝!!!

發佈了9 篇原創文章 · 獲贊 1 · 訪問量 1105
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章