OVS 中的 upcall 執行緒

張浮生發表於2017-06-05

總體概覽如下:

假設upcall handler執行緒有兩個,vport有四個,那麼每個vport下都將持有兩個NetLink連線的資訊,這兩個NetLink連線將被用來上送upcall訊息。
每個NetLink連線被對應的upcall handler執行緒接管,多個vport在同一執行緒中的NetLink連線被epoll管理。

 

1:每個vport下都掛多個NetLink連線,數量等同於upcall處理執行緒的數量
2:執行緒中routine函式為udpif_upcall_handler,偽碼如下:
     routine {
          while(執行緒不設自殺標記) {
               if(從epoll中收到了一些upcall訊息,則進一步處理upcall) {
                    continue; 
               } else {
                    註冊poll:當epoll_fd有騷動時解除當前執行緒的block
               }
               block當前執行緒
          }
     }
3:每個NetLink連線被稱為一個upcall channel
 
1:upcall處理執行緒的建立
upcall處理執行緒隨著vswitchd程式的啟動而被建立,概覽如下:

 

最終所有執行緒資訊會被記錄在 ofproto_dpif->backer->udpif下
 
2:vport的建立與channels的建立
在基於本機核心的datapath實現的openflow交換機場景下,使用者態的datapath介面將採用dpif_netlink_***系列函式。vport的建立在使用者態最終將呼叫到dpif_netlink_port_add,這是dpif_netlink_port_add__的包裹函式。
 
先說一點我對NetLink連線的理解
     1:建立socket
     2:可選的bind步驟,在這一步,應當在本端地址結構中賦值nl_pid為當前程式ID,並bind之。
     3:建立連線connect,這一步對端地址結構的nl_pid值如果為非0值 ,那麼連線的就是一個使用者態程式。如果nl_pid值為0,則連線的是核心。
     如果沒有第2步,那麼在connect之後,核心會為這個NetLink連線的本端bind地址結構自動指定一個nl_pid值,以標識該連線。此時通過getsockname取到的本端地址結構中的nl_pid欄位將不是發起連線一方的程式ID。

 

3:核心cache miss
核心cache miss後,會傳送upcall訊息,
 
netdev_frame_hook(pskb)
    |
    \-> netdev_port_receive(skb, NULL/skb_tunnel_info(skb))
        |
        \-> ovs_vport_receive(ovs_netdev_get_vport(skb->dev), skb, tun_info = NULL/skb_tunnel_info(skb))
            |
            \-> error = ovs_flow_key_extract(tun_info, skb, &key)
            |
            \-> ovs_dp_process_packet(skb, &key)
                |
                \-> flow = ovs_flow_tbl_lookup_stats(&dp->table, key, skb_get_hash(skb), &n_mask_hit)
                    if(unlikely(!flow)) {
                        ...
                        upcall.cmd = OVS_PACKET_CMD_MISS;
                        upcall.portid = ovs_vport_find_upcall_portid(p, skb);
                        |
                        \-> vport下的upcall_portids裡欽定一個port號,作為NetLink的目的地
                        ...
                        error = ovs_dp_upcall(dp, skb, key, &upcall, 0);
                    }
即是從upcall的vport下掛的socksp中選擇一個nl_pid,以這個nl_pid做為upcall訊息傳送的目的地址
由上面的圖能看出來,在vport下選擇不同的socksp中的nl_pid,會導致訊息被髮往不同的epoll
 
 
4:dpif_handler[]->epoll_fd與使用者態執行緒間的關聯

 

那麼在udpif_upcall_handler() -> recv_upcalls() -> dpif_recv() -> dpif_netlink_recv() -> dpif_netlink_recv__()中有以下程式碼:
 

 

這裡的引數handler_id來自於執行緒routine函式的入參handler例項下的handler_id。
即對於x號執行緒,它會取dpif_handler[]陣列中的x號元素下的epoll_fd去處理。

 

相關文章