最近嘗試了dpdk
的kni
驅動,使得非高速**路徑的資料能利用kernel協議棧,這確實方便了非面向效能的應用。不過在kni
虛擬介面上執行多播應用的時候的時候發現,根本不工作?
談談nic的多播接收
接收多播對於乙個網絡卡來說是必須的,然而初始情況下ethernet網絡卡只接收兩類資料幀:
除非,這也是為什麼多播的效率好於廣播的原因,本機不關心的多播在硬體層就ignore,不必麻煩協議棧。由於應用程式或協議(igmp/mld
、ipv6 slaac/nd
,ospf
等)本身的需求,要加入乙個多播組的時候,例如224.0.0.1
,將其轉化為乙太網多播位址(01:00:5e:00:00:01
)然後告知網絡卡要接受這個多播幀。
網絡卡一般會有乙個表維護要加入哪些多播,因為資源的限制,不可能做到為每個乙太網多播維護乙個很大的表,會採用雜湊的形式多對一對映,或者限制多播表的大小。怎麼
kni
裝置收不到多播?
回到kni
的情況,網絡卡本身顯然是支援多播的,以防萬一,查了下dpdk的nic驅動也是支援的;那麼只能懷疑kni
虛擬裝置的驅動了,果然,kni
驅動「實現了」設定多播的函式ndo_set_rx_mode()
,只不過是個空函式而已。
kni是虛擬裝置,轉交pmd裝置的包,不關心是不是多播,本來是「沒必要」實現這個邏輯的。不過既然kni是建立在實際pmd裝置之上的虛擬linux裝置,linux只能操作到ndo_***
系列函式(包括ndo_set_rx_mode
)是kernelnet_device
層和具體裝置驅動的乙個callback(虛函式),實現ndo_set_rx_mode
目的是控制網絡卡的接收模式。換句話說就是設定nic位址過濾表,除了自己位址和廣播外,額外置收哪些硬體位址,比如,
kni
驅動,需要把dpdk pmd控制下的物理網絡卡的多播開啟才行。
double check下最新的release,沒有填坑的跡象。
那麼只能自己動手了
網絡卡硬體是ok的,pdm驅動也是支援多播的(雖然只是提供了個api讓使用者自己設定)。那麼目標很明確,通過kni
驅動把需要加入的mac多播告知實際控制網絡卡的pmd
驅動即可。分成幾個步驟,
kernel把多播列表存在哪?
去設定多播的地方找找(除非你知道它們就在net_device->mc
裡面),
ip_mc_join_group()硬體多播被作為|- ip_mc_find_dev
|- ip_mc_inc_group
|- ipv4多播被加入了dev.in_device.mc_hash/.mc_list
|- igmp_group_added
|- ip_mc_filter_add
|- dev_mc_add
|- __hw_addr_add_ex
| 分配netdev_hw_addr加入dev->mc列表
|- __dev_set_rx_mode
|- dev.ops.ndo_set_rx_mode
設定具體驅動的rx mode
netdev_hw_addr
儲存在了dev->mc
列表之中,並通過之前提到的ndo_set_rx_mode
傳遞給具體的驅動。「helper」巨集netdev_for_each_mc_addr
可以用來遍歷該鍊錶。
kni
怎麼通知pmd
?
dpdk的pmd是使用者態驅動,kni
驅動是核心態的,他們之間的通過記憶體對映實現的fifo來通訊,包括資料報和控制訊息。具體可以參考kni的文件和**。
kni
和pmd
控制通道是sync fifo
,對應了kni_dev.sync_kva/va
。具體說來是用了上面的那段記憶體來傳輸rte_kni_request
結構的,kernel可以使用apikni_net_process_request
傳送請求到使用者態;使用者態由rte_kni_handle_request
處理請求,返回處理結果。
但是requset結構目前只支援通知 mtu改變和link狀態改變;為了傳遞多播列表需要自定義乙個訊息型別以及儲存多播的結構放到requset結構。
考慮到畢竟mtu和link up/down這種訊息相對乙個多播列表而言資料量很小,擔心乙個多播列表儲存request超過kni_dev.sync_kva/va
的大小(畢竟表面上看不出它到底多大呀!)。追查了分配這個buffer的地方:rte_kni_init()/memzone "kni_sync_%d"
,差不多有64k大,放心了。
利用sync fifo
是不是好?不好說,只是使用別的kernel/user-space通訊方式,也有點繁瑣。
定義資料結構,從net_dev->mc
提取mac多播,用request傳遞給pmd,記得處理response。
pmd驅動多播列表設定到實際網絡卡中
這個簡單,在rte_kni_handle_request
接收到kernel的訊息直接呼叫api即可。
最後還有一點要注意,ndo_set_rx_mode
是在原子(spinlock)上下文,而kni_net_process_request
呼叫了mutex
,原子上下文不能使用mutex
這種會引發上下文切換的函式。所以在ndo_set_rx_mode
裡將多播列表暫時儲存起來然後利用kni
的kthread
執行緒去檢查並傳送請求,後者訪問dev->mc
資料的時候記得上鎖(netdev_addr_lock_bh
)並一次性取出。
多播在kni
虛擬介面上正常接收,可以,這很diy
Windows多網絡卡環境接收組播包
說明 本文僅針對ipv4 區域網發現技術有很多,常用組播 或稱為多播 一台裝置傳送組播包,其他裝置加入組播組,接收到組播包時即可知曉傳送端ip,接收端回應約定資料即可讓傳送端也得知這些接收端的ip。ipv4的d類位址 224.0.0.0至239.255.255.255 是ipv4多播位址。d類位址的...
多播的步驟
1.建立socket socketfd socket af inet,sock dgram,0 if 1 socketfd 2.設定socket可重用並繫結 loop 1 if setsockopt socketfd,sol socket,so reuseaddr,loop,sizeof loop ...
UDP的組播與多播
在前面已經記錄過udp的單播模式,即客戶端只能與服務端單獨對接。接下來介紹udp的另外兩種通訊方式 udpsocket newqudpsocket this udpsocket bind qhostaddress 192.168.1.100 45454 qbytearray datagram mul...