17.14. 多播

2018-02-24 15:50 更新

17.14.?多播

一個多播報文是一個會被多個主機接收的網(wǎng)絡(luò)報文, 但不是所有主機. 這個功能通過給一組主機分配特殊的硬件地址來獲得. 發(fā)向一個特殊地址的報文應(yīng)當被那個組當中的所有主機接收. 在以太網(wǎng)的情況下, 一個多播地址在目的地址的第一個字節(jié)的最低位為 1, 而每個設(shè)備板在它自己的硬件地址的這一位上為 0.

處理主機組和硬件地址的技巧由應(yīng)用程序和內(nèi)核處理, 接口驅(qū)動不必處理這個問題.

多播報文的傳送是一個簡單問題, 因為它們看起來就如同其他的報文. 接口發(fā)送它們通過通訊媒介, 不查看目的地址. 內(nèi)核必須要安排一個正確的硬件目的地址; hard_header 設(shè)備方法, 如果定義了, 不必查看它安排的數(shù)據(jù).

內(nèi)核來跟蹤在任何給定時間對哪些多播地址感興趣. 這個列表可能經(jīng)常改變, 因為它是在任何給定時間和按照用戶意愿運行的應(yīng)用程序的功能. 驅(qū)動的工作是接收感興趣的多播地址列表并遞交給內(nèi)核任何發(fā)向這些地址的報文. 驅(qū)動如何實現(xiàn)多播列表是依賴于底層硬件是如何工作的. 典型地, 在多播的角度上, 硬件屬于 3 類中的 1 種:

  • 不能處理多播的接口. 這樣的接口要么接收特別地發(fā)向它們的硬件地址(加上廣播報文)的報文, 要么接收每一個報文. 它們只能通過接收每一個報文來接收多播報文, 因此, 潛在地壓垮操作系統(tǒng), 使用大量的"不感興趣"報文. 你不經(jīng)常認為這樣的接口是有多播能力的, 驅(qū)動不會在 dev->flags 設(shè)置 IFF_MULTICAST.

點對點接口是特殊情況, 因為它們一直接收每個報文, 不進行任何硬件過濾.

  • 能夠區(qū)別多播報文和其他報文(主機到主機, 或者廣播). 這些接口能夠被命令來接收每個多播報文, 讓軟件決定地址是否是主機感興趣的. 這種情況下的開銷是可接受的, 因為在一個典型網(wǎng)絡(luò)上的多播報文的數(shù)目是少的.

  • 可以進行硬件檢測多播地址的接口. 可以傳遞一個多播地址的列表給這些接口, 這些地址的報文接收, 并忽略其他多播地址的報文. 對內(nèi)核這是優(yōu)化的情況, 因為它不浪費處理器時間來丟棄接口收到的"不感興趣"的報文.

內(nèi)核盡力利用高級接口的能力, 通過支持第 3 種設(shè)備類型, 它是最通用的. 因此, 內(nèi)核通知驅(qū)動, 在任何有效多播地址列表發(fā)生改變時, 并且它傳遞新的列表給驅(qū)動, 因此它能夠根據(jù)新的信息來更新硬件過濾器.

17.14.1.?多播的內(nèi)核支持

對多播報文的支持有幾項組成:一個設(shè)備方法, 一個數(shù)據(jù)結(jié)構(gòu), 以及設(shè)備標識:

void (dev->set_multicast_list)(struct net_device dev);
設(shè)備方法, 在與設(shè)備相關(guān)的機器地址改變時調(diào)用. 它也在 dev->flags 被修改時調(diào)用, 因為一些標志(例如, IFF_PROMISC) 可能也要求你重新編程硬件過濾器. 這個方法接收一個 struct net_device 指針作為一個參數(shù), 并返回 void. 一個對實現(xiàn)這個方法不感興趣的驅(qū)動可以聽任它為 NULL.

struct dev_mc_list *dev->mc_list;
所有設(shè)備相關(guān)的多播地址的列表. 這個結(jié)構(gòu)的實際定義在本節(jié)的末尾介紹.

int dev->mc_count;
鏈表里的項數(shù). 這個信息有些重復, 但是用 0 來檢查 mc_count 是檢查這個列表的有用的方法.

IFF_MULTICAST
除非驅(qū)動在 dev->flags 中設(shè)置這個標志, 接口不會被要求來處理多播報文. 然而, 內(nèi)核調(diào)用驅(qū)動的 set_multicast_list 方法, 當 dev->flags 改變時, 因為多播列表可能在接口未激活時改變了.

IFF_ALLMULTI
在 dev->flags 中設(shè)置的標志, 網(wǎng)絡(luò)軟件來告知驅(qū)動從網(wǎng)絡(luò)上接收所有多播報文. 這發(fā)生在當多播路由激活時. 如果標志設(shè)置了, dev->ma_list 不該用來過濾多播報文.

IFF_PROMISC

在 dev->flags 中設(shè)置的標志, 當接口在混雜模式下. 接口應(yīng)當接收每個報文, 不管 dev->ma_list.

驅(qū)動開發(fā)者需要的最后一點信息是 struct dev_mc_list 的定義, 在 <linux/netdevice.h>:


struct dev_mc_list { struct dev_mc_list *next; /* Next address in list */
    __u8 dmi_addr[MAX_ADDR_LEN]; /* Hardware address */
    unsigned char  dmi_addrlen;  /* Address length */
    int  dmi_users;  /* Number of users */
    int  dmi_gusers;  /* Number of groups */
};

因為多播和硬件地址是獨立于真正的報文發(fā)送, 這個結(jié)構(gòu)在網(wǎng)絡(luò)實現(xiàn)中是可移植的, 每個地址由一個字符串和一個長度標識, 就像 dev->dev_addr.

17.14.2.?典型實現(xiàn)

描述 set_multicast_list 的設(shè)計的最好方法是給你看一些偽碼.

下面的函數(shù)是一個典型函數(shù)實現(xiàn)在一個全特性(ff)驅(qū)動中. 這個驅(qū)動是全模式的, 它控制的接口有一個復雜的硬件報文過濾器, 它能夠持有一個主機要接收的多播地址表. 表的最大尺寸是 FF_TABLE_SIZE.

所有以 ff_ 前綴的函數(shù)是給特定硬件操作的占位者:


void ff_set_multicast_list(struct net_device *dev) { struct dev_mc_list *mcptr;
    if (dev->flags & IFF_PROMISC) {
        ff_get_all_packets();
        return;

    }
    /* If there's more addresses than we handle, get all multicast
    packets and sort them out in software. */
    if (dev->flags & IFF_ALLMULTI || dev->mc_count > FF_TABLE_SIZE) {

        ff_get_all_multicast_packets();
        return;
    }
    /* No multicast? Just get our own stuff */
    if (dev->mc_count == 0) {
        ff_get_only_own_packets();
        return;
    }
    /* Store all of the multicast addresses in the hardware filter */
    ff_clear_mc_list();
    for (mc_ptr = dev->mc_list; mc_ptr; mc_ptr = mc_ptr->next)
        ff_store_mc_address(mc_ptr->dmi_addr);
    ff_get_packets_in_multicast_list();
}

這個實現(xiàn)可以簡化, 如果接口不能為進入報文存儲多播表在硬件過濾器中. 這種情況下, FF_TABLE_SIZE 減為 0, 并且代碼的最后 4 行不需要了.

如同前面提過的, 不能處理多播報文的接口不需要實現(xiàn) set_multicast_list 方法來獲取 dev->flags 改變的通知. 這個辦法可能被稱為一個"非特性的"(nf)實現(xiàn). 實現(xiàn)非常簡單, 如下面代碼所示:


void nf_set_multicast_list(struct net_device *dev)
{
    if (dev->flags & IFF_PROMISC)
        nf_get_all_packets();
    else
        nf_get_only_own_packets();
}

實現(xiàn) IFF_PROMISC 是非常重要的, 因為不這樣用戶就不能運行 tcpdump 或任何其他網(wǎng)絡(luò)分析器. 如果接口運行一個點對點連接, 另一方面, 根本沒有必要實現(xiàn) set_multicast_list, 因為用戶接收每個報文.

以上內(nèi)容是否對您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號
微信公眾號

編程獅公眾號