<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之旅 廣告
                這來主要看看ovs從網絡接口收到packet后的一系列操作。 在內核模塊啟動的時候會初始化vport子系統(ovs_vport_init),各種vport類型,那么什么時候會調用相應的函數與實際網絡設備建立聯系?其實當我們在為網橋增設端口的時候,就會進入ovs_netdev_vport_ops中的create方法,進而 注冊網絡設備。 看[ovs-vsctl add-port br0 eth1?實際做了什么?](http://blog.csdn.net/vonzhoufz/article/details/19981911) ~~~ struct?netdev_vport?{ ??? struct rcu_head rcu; ???struct net_device *dev; }; const struct vport_ops?ovs_netdev_vport_ops?= { ??? .type????????? = OVS_VPORT_TYPE_NETDEV, ??? .flags????????? = VPORT_F_REQUIRED, ????.init????????? = netdev_init, ??//之后的內核版本,這里直接return 0; ??? .exit????????? = netdev_exit, ????.create????????? = netdev_create, ??? .destroy???? = netdev_destroy, ??? .set_addr???? = ovs_netdev_set_addr, ??? .get_name???? = ovs_netdev_get_name, ??? .get_addr???? = ovs_netdev_get_addr, ??? .get_kobj???? = ovs_netdev_get_kobj, ??? .get_dev_flags???? = ovs_netdev_get_dev_flags, ??? .is_running???? = ovs_netdev_is_running, ??? .get_operstate???? = ovs_netdev_get_operstate, ??? .get_ifindex???? = ovs_netdev_get_ifindex, ??? .get_mtu???? = ovs_netdev_get_mtu, ??? .send????????? = netdev_send, }; --datapath/vport-netdev.c static struct vport *netdev_create(const struct vport_parms *parms) { ??? struct vport *vport; ??? struct netdev_vport *netdev_vport; ??? int err; ??? vport = ovs_vport_alloc(sizeof(struct netdev_vport),? ?&ovs_netdev_vport_ops, parms); ? ?//有ovs_netdev_vport_ops和vport parameters 來構造初始化一個vport; ? ?netdev_vport = netdev_vport_priv(vport); ? ?//獲得vport私有區域?? ????netdev_vport->dev = dev_get_by_name(ovs_dp_get_net(vport->dp), parms->name); ???[//通過interface]()?name比如eth0 得到具體具體的net_device 結構體,然后下面注冊 rx_handler; ??? if (netdev_vport->dev->flags & IFF_LOOPBACK ||? netdev_vport->dev->type != ARPHRD_ETHER || ??? ????ovs_is_internal_dev(netdev_vport->dev)) { ???????? err = -EINVAL; ???????? goto error_put; ??? } ???//不是環回接口;而且底層鏈路層是以太網;netdev->netdev_ops == &internal_dev_netdev_ops 顯然為false ????err =?netdev_rx_handler_register(netdev_vport->dev, netdev_frame_hook,?vport); ? ??[//核心,收到packet后會調用]()?netdev_frame_hook處理; ??? dev_set_promiscuity(netdev_vport->dev, 1); ?//設置為混雜模式; ??? netdev_vport->dev->priv_flags |= IFF_OVS_DATAPATH; ?//設置netdevice私有區域的標識; ??? return vport; } --datapath/vport.h 創建vport所需要的參數結構 struct?vport_parms?{ ??? const char *name; ? ? ??? enum ovs_vport_type type; ??? struct nlattr *options; ??[//利于必要的時候從 netlink msg通過屬性OVS_VPORT_ATTR_OPTIONS取得 ]() ??? /* For ovs_vport_alloc(). */ ????struct datapath *dp; ?// 這個vport所從屬的datapath ??? u16 port_no; ? //端口號 ????u32 upcall_portid;?// 如果從這個vport收到的包 在flow table沒有得到匹配就會從 netlink端口upcall_portid 發送到用戶空間; }; ~~~ 函數netdev_rx_handler_register(struct net_device *dev,rx_handler_func_t *rx_handler, void *rx_handler_data)定義在 linux/netdevice.h 實現在 net/core/dev.c 中,為網絡設備dev注冊一個receive handler,rx_handler_data指向的是這個receive handler是用的內存區域(這里存的是vport,里面有datapath的相關信息)。這個handler 以后會被 __netif_receive_skb() 呼叫,實際就是更新netdevice中的兩個指針域,rcu_assign_pointer(dev->rx_handler_data, rx_handler_data),? rcu_assign_pointer(dev->rx_handler, rx_handler) 。 ? netif_receive_skb(struct sk_buff *skb)從網絡中接收數據,它是主要的接收數據處理函數,總是成功,這個buffer在擁塞處理或協議層的時候可能被丟棄。這個函數只能從軟中斷環境(softirq context)中調用,并且中斷允許。返回值?NET_RX_SUCCESS表示沒有擁塞,NET_RX_DROP包丟棄。(實現細節暫時沒看) 接下來進入我們的鉤子函數 netdev_frame_hook(datapath/vport-netdev.c)這里主要看內核版本>=2.6.39的實現。 ~~~ ? ?static rx_handler_result_t?netdev_frame_hook(struct sk_buff **pskb) { ??? struct sk_buff *skb = *pskb; ??? struct vport *vport; ??? if (unlikely(skb->pkt_type == PACKET_LOOPBACK)) ???????? return RX_HANDLER_PASS; ??? vport = ovs_netdev_get_vport(skb->dev); ? ?//提攜出前面存入的那個vport結構體,vport-netdev.c line 401; ????netdev_port_receive(vport, skb); ??? return RX_HANDLER_CONSUMED; } ~~~ 函數 netdev_port_receive 首先得到一個packet的拷貝,否則會損壞先于我們而來的packet使用者?(e.g. tcpdump via AF_PACKET),我們之后沒有這種情況,因為會告知handle_bridge()我們獲得了那個packet 。 skb_push是將skb的數據區向后移動*_HLEN長度,為了存入幀頭;而skb_put是擴展數據區后面為存數據memcpy做準備。 ~~~ static void?netdev_port_receive(struct vport *vport, struct sk_buff *skb) { ? ?skb = skb_share_check(skb, GFP_ATOMIC); ? ? //GFP_ATOMIC用于在中斷處理例程或其它運行于進程上下文之外的地方分配內存,不會休眠(LDD214)。 ??? skb_push(skb, ETH_HLEN); ? ?//疑問:剛接收到的packet應該是有 ether header的,為何還執行這個操作?? ??? if (unlikely(compute_ip_summed(skb, false))) ???????? goto error; ??? vlan_copy_skb_tci(skb); // <2.6.27版本的時候才需要VLAN field; ????ovs_vport_receive(vport, skb); ??? return; ? ? ................. } ~~~ 接下來將收到的packet傳給datapath處理(datapath/vport.c),參數vport是收到這個包的vport(表征物理接口和datapath),skb是收到的數據。讀的時候要用rcu_read_lock,這個包不能被共享而且skb->data?應該指向以太網頭域,而且調用者要確保已經執行過?compute_ip_summed()?初始化那些校驗和域。 ~~~ void?ovs_vport_receive(struct vport *vport, struct sk_buff *skb) { ??? struct vport_percpu_stats *stats; ??? stats = per_cpu_ptr(vport->percpu_stats, smp_processor_id()); ? ?//每當收發數據的時候更新這個vport的狀態(包數,字節數),struct vport_percpu_stats定義在vport.h中。 ??? u64_stats_update_begin(&stats->sync); ??? stats->rx_packets++; ??? stats->rx_bytes += skb->len; ??? u64_stats_update_end(&stats->sync); ??? if (!(vport->ops->flags & VPORT_F_FLOW)) ???????? OVS_CB(skb)->flow = NULL; ? ?[//vport->ops->flags]()?(VPORT_F_*)影響的是這個通用vport層如何處理這個packet; ??? if (!(vport->ops->flags & VPORT_F_TUN_ID)) ???????? OVS_CB(skb)->tun_key = NULL; ????ovs_dp_process_received_packet(vport, skb); } ~~~ 接下來我們的datapath模塊來處理傳上來的packet(datapath/datapath.c),首先我們要判斷如果存在skb->cb域中的OVS ?data sw_flow 是空的話,就要從packet中提攜構造;函數?ovs_flow_extract 從以太網幀中構造 sw_flow_key,為接下來的流表查詢做準備;流表結構struct flow_table定義在flow.h中,流表實在ovs_flow_init的時候初始化的?? 如果沒有match成功,就會upcall遞交給用戶空間處理(見vswitchd模塊分析),匹配成功的話執行flow action(接下來就是openflow相關)。 ~~~ 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; ??? u64 *stats_counter; ??? int error; ??? stats = per_cpu_ptr(dp->stats_percpu, smp_processor_id()); ??? if (!OVS_CB(skb)->flow) { ???????? struct sw_flow_key key; ???????? int key_len; ? ? ? ?/* Extract flow from 'skb' into 'key'. */ ???????? error =?ovs_flow_extract(skb, p->port_no, &key, &key_len); ? ? ?? ? ? ? ? /* Look up flow. */ ???????? flow =?ovs_flow_tbl_lookup(rcu_dereference(dp->table),? &key, key_len); ???????? if (unlikely(!flow)) { ????????????? struct dp_upcall_info upcall; ????????????? upcall.cmd = OVS_PACKET_CMD_MISS; ????????????? upcall.key = &key; ????????????? upcall.userdata = NULL; ????????????? upcall.portid = p->upcall_portid; ??????????????ovs_dp_upcall(dp, skb, &upcall); ????????????? consume_skb(skb); ????????????? stats_counter = &stats->n_missed; ????????????? goto out; ???????? } ???????? OVS_CB(skb)->flow = flow; ??? } ??? stats_counter = &stats->n_hit; ??? ovs_flow_used(OVS_CB(skb)->flow, skb); ????ovs_execute_actions(dp, skb); out: ??? /* Update datapath statistics. */ ??? u64_stats_update_begin(&stats->sync); ??? (*stats_counter)++; ??? u64_stats_update_end(&stats->sync); } ~~~ 轉載地址:http://blog.csdn.net/vonzhoufz/article/details/19840683
                  <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>

                              哎呀哎呀视频在线观看