<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                ThinkChat2.0新版上線,更智能更精彩,支持會話、畫圖、視頻、閱讀、搜索等,送10W Token,即刻開啟你的AI之旅 廣告
                上篇分析到數據包的收發,這篇開始著手分析數據包的處理問題。在openVswitch中數據包的處理是其核心技術,該技術分為三部分來實現:第一、根據skb數據包提取相關信息封裝成key值;第二、根據提取到key值和skb數據包進行流表的匹配;第三、根據匹配到的流表做相應的action操作(若沒匹配到則調用函數往用戶空間傳遞數據包);其具體的代碼實現在 datapath/datapath.c 中的,函數為:?void ovs_dp_process_received_packet(struct vport *p, struct sk_buff *skb);當接受到一個數據包后,自然而然的就應該是開始對其進行處理了。所以其實在上篇的[openVswitch(OVS)源代碼分析之工作流程(收發數據包)](http://blog.csdn.net/yuzhihui_no1/article/details/39298321)中的接受數據包函數:void ovs_vport_receive(struct vport *vport, struct sk_buff *skb)中已有體現,該函數在最后調用了ovs_dp_process_received_packet(struct vport *p, struct sk_buff *skb);來把數據包傳遞到該函數中去進行處理。也由此可見所有進入到openVswitch的數據包都必須經過ovs_dp_process_received_packet(struct vport *p, struct sk_buff *skb);函數的處理。所以說ovs_dp_process_received_packet(struct vport *p, struct sk_buff *skb);是整個openVswitch的中間樞紐,是openVswitch的核心部分。 對于ovs_dp_process_received_packet(struct vport *p, struct sk_buff *skb);的重要性已經解釋的非常清楚,緊接著就應該分析該函數源代碼了,在分析源代碼之前還是得提醒下,其中涉及到很多數據結構,如果有些陌生可以到[openVswitch(OVS)源代碼分析之數據結構](http://blog.csdn.net/yuzhihui_no1/article/details/39188373)中進行查閱,最好能先大概的看下那文章,了解下其中的數據結構,對以后分析源代碼有很大的幫助。 下面來分析幾個ovs_dp_process_received_packet(struct vport *p, struct sk_buff *skb);函數中涉及到但在[openVswitch(OVS)源代碼分析之數據結構](http://blog.csdn.net/yuzhihui_no1/article/details/39188373)又沒有分析到的數據結構: 第一個、是數據包的統計結構體,是CPU用來對所有數據的一個統計作用: ~~~ // CPU對給定的數據包處理統計 struct dp_stats_percpu { u64 n_hit; // 匹配成功的數據包個數 u64 n_missed; // 匹配失敗的數據包個數,n_hit + n_missed就是接受到的數據包總和 u64 n_lost; // 丟失的數據包個數(可能是datapath隊列溢出導致) struct u64_stats_sync sync; }; ~~~ 第二、是數據包發送到用戶空間的參數結構體,在匹配流表沒有成功時,數據將發送到用戶空間。而內核空間和用戶空間進行數據交互是通過netLinks來實現的,所以這個函數就是為了實現netLink通信而設置的一些參數: ~~~ // 把數據包傳送給用戶空間所需的參數結構體 struct dp_upcall_info { u8 cmd; // 命令,OVS_PACKET_CMD_ *之一 const struct sw_flow_key *key; // key值,不能為空 const struct nlattr *userdata; // 數據的大小,若為空,OVS_PACKET_ATTR_USERDATA傳送到用戶空間 u32 portid; // 發送數據包的Netlink的PID,其實就是netLink通信的id號 }; ~~~ 下面是來分析ovs_dp_process_received_packet(struct vport *p, struct sk_buff *skb);函數的實現源代碼: ~~~ // 數據包的處理函數,openVswitch的核心部分 void ovs_dp_process_received_packet(struct vport *p, struct sk_buff *skb) { struct datapath *dp = p->dp; // 定義網橋變量,得到端口所在的網橋指針 struct sw_flow *flow; // 流表 struct dp_stats_percpu *stats; // cpu中對數據包的統計 struct sw_flow_key key; // skb中提取到的key值 u64 *stats_counter; int error; // 這應該是linux內核中的,openVswitch中很多是根據linux內核設計而來的 // 這里應該是對網橋中的數據包統計屬性進行初始化 stats = this_cpu_ptr(dp->stats_percpu); // 根據端口和skb數據包的相關值進行提取,然后封裝成key值 error = ovs_flow_extract(skb, p->port_no, &key); if (unlikely(error)) { // 定義宏來判斷key值得提取封裝是否成功 kfree_skb(skb);// 如果沒有成功,則銷毀掉skb數據包,然后直接退出 return; } // 調用函數根據key值對流表中所有流表項進行匹配,把結果返回到flow中 flow = ovs_flow_lookup(rcu_dereference(dp->table), &key); if (unlikely(!flow)) { // 定義宏判斷是否匹配到相應的流表項,如沒有,執行下面代碼 struct dp_upcall_info upcall; // 定義一個結構體,設置相應的值,然后把數據包發送到用戶空間 // 下面是根據dp_upcall_info數據結構,對其成員進行填充 upcall.cmd = OVS_PACKET_CMD_MISS;// 命令 upcall.key = &key;// key值 upcall.userdata = NULL;// 數據長度 upcall.portid = p->upcall_portid;// netLink通信時的id號 ovs_dp_upcall(dp, skb, &upcall);// 把數據包發送到用戶空間 consume_skb(skb);// 銷毀skb stats_counter = &stats->n_missed;// 用未匹配到流表項的包數,給計數器賦值 goto out;// goto語句,內部跳轉,跳轉到out處 } // 在分析下面的代碼時,先看下OVS_CB()這個宏:#define OVS_CB(skb) ((struct ovs_skb_cb *)(skb)->cb) // 這個宏如果知道skb數據結構的話,就好理解。大概的意思是把skb中保存的當前層協議信息的數據強轉為ovs_skb_cb*數據指針 OVS_CB(skb)->flow = flow;// 能夠執行到這里,說明匹配到了流表。把匹配到的流表想flow賦值給結構體中成員 OVS_CB(skb)->pkt_key = &key;// 同上,把相應的key值賦值到結構體變量中 // 這是匹配成功的,用匹配成功的數據包數賦值于計數器變量 stats_counter = &stats->n_hit; ovs_flow_used(OVS_CB(skb)->flow, skb);// 調用函數調整流表項成員變量(也許是用來流表項的更新) ovs_execute_actions(dp, skb); // 根據匹配到的流表項(已經在skb中的cb)執行相應的action操作 out: // 這是流表匹配失敗,數據包發到用戶空間后,跳轉到該處, // 對處理過的數據包數進行調整(雖然沒匹配到流表,但也算是處理掉了一個數據包,所以計數器變量應該增加1) u64_stats_update_begin(&stats->sync); (*stats_counter)++; u64_stats_update_end(&stats->sync); } ~~~ 上面就是openVswitch的核心部分,所有的數據包都要經過此函數進行邏輯處理。這只是一個邏輯處理的大體框架,還有一些細節(key值得提取,流表的匹配查詢,數據傳輸到用戶空間,根據流表執行相應action)將在后面分析。當把整個openVswitch的工作流程梳理清晰,會發現這其實就是openVswitch的頭腦部分,所有的邏輯處理都在里實現,所以我們自己添加代碼時,這里往往也是個不錯的選擇。 如果看了前面那篇[openVswitch(OVS)源代碼分析之工作流程(收發數據包)](http://blog.csdn.net/yuzhihui_no1/article/details/39298321),那么應該記得其中也說到了可以在收發函數中添加自己代碼,因為一般來說收發函數也是數據包的必經之地(發送函數可能不是)。那么怎么區分在哪里添加自己代碼合適呢? 其實在接受數據包函數中添加自己代碼和在這里的邏輯處理函數中添加自己代碼,沒有多大區別,因為接受函數中沒有做什么處理就把數據包直接發送打邏輯處理函數中去了,所以這兩個地方添加自己代碼其實是沒什么區別的。但是從習慣和規范來說,數據包接受函數只是根據條件控制數據包的接受,并不對數據包進行邏輯上的處理,也不會對數據包進行修改等操作。而邏輯處理函數是會對數據包進行某些邏輯上的處理。(最明顯的是修改數據包內的數據,一般來說接受數據包函數中是不會對數據包內容修改的,但邏輯處理函數則有可能會去修改的)。 而在數據包發送函數中添加自己代碼和邏輯函數中添加自己代碼也有些區別,數據包發送函數其性質和接受函數一樣,一般不會去修改數據包,而僅僅是根據條件判斷該數據包是否發送而已。 那下面就邏輯處理函數中添加代碼來舉例: 假若要把某個指定的IP主機上發來的ARP數據包進行處理,把所有的請求數據包變成應答數據包,原路返回。這里最好就是把自己的代碼添加到邏輯處理函數中去(如果你要強制的添加到數據包接受函數中去也可以),因為這里要修改數據包的內容,是一個邏輯處理。具體實現:可以在key值提取前對數據包進行判斷,看是否是ARP數據包,并且是否是指定IP主機發來的。若不是,交給系統去處理;若是,則對Mac地址和IP地址進行交換,并且把請求標識變成應答標識;最后調用發送函數從原來的端口直接發送出去。這只是一個簡單的應用,旨在說明邏輯處理代碼最好添加到邏輯處理函數中去。如果要處理復雜的操作也是可以的,比如定義自己的流表,然后然后屏蔽掉系統的流表查詢,按自己的流表來操作。這就是一個對openVswitch比較大的改造了,流表、action、流表匹配等這些openVswitch主要功能和結構都要自己去定義實現完成。 以上分析得就是openVswitch的核心部分,當然了只是一個大體框架而已,后續將會逐步完善。 轉載請注明原文出處,原文地址:[http://blog.csdn.net/yuzhihui_no1/article/details/39378195](http://blog.csdn.net/yuzhihui_no1/article/details/39378195) 如有不正確之處,望大家指正,謝謝!!!
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看