《TCP/IP具体解释卷2:实现》笔记--IP多播

时间:2022-05-17 11:48:29

D类IP地址(224.0.0.0到239.255.255.255)不识别互联网内的单个接口,但识别接口组,被称为多播组。

单个网络上的组成员利用IGMP协议在系统之间通信。

多播路由器用多播选录协议。如DVMRP(distance vector multicast

routing protocol。距离向量多播路由选择协议)传播成员信息。

在Net/3中,假设某个接口支持多播。那么在接口ifnet结构中的if_flags的标识IFF_MULTICAST比特就被打开。

RFC 1112描写叙述了多播对主机的要求,分三个级别:

0级:主机不能发送或接受IP。

折中主机应该自己主动丢弃它收到的具有D类目的地址的分组。

1级:主机能发送但不能接受IP多播。

在向某个IP多播组发送数据报之前,并不要求主机增加该组。多播数据报的发送方式与单播一样,除了多播数据报的目的地址

是IP多播组之外。

网络驱动器必须可以识别出这个地址。

2级:主机能发送和接收IP多播

为了接收IP多播。主机必须可以增加或离开多播组,并且必须支持IGMP。可以在至少一个接口上交换组成员信息。多接口主机

必须支持在它的接口的一个子网上的多播。Net/3符合2级主机要求。能够完毕多播路由器的工作。

和UDP、TCP的port号一样。互联网授权机构IANA(Internet Assigned Numbers Authority)维护着一个注冊的IP多播组表。

下图

仅仅给出了一些知名的多播组。

《TCP/IP具体解释卷2:实现》笔记--IP多播

watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvVE9ERDkxMQ==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center" alt="">

全256个组(224.0.0.0到224.0.0.255)是为实现IP单播和多播选路机制的协议预留的。无论发给当中随意一个组的数据报内IP

首部的TTL值怎样变化。多播路由器都不会把它转发出本地网络。

对于符合2级的系统,要求其在系统初始化时。在全部的多播接口上增加224.0.0.1组,而且保持该组成员,直到系统关闭。

单播和多播路由可能会增加224.0.0.2组进行互相通信。

ICMP路由器请求报文和路由器通告可能会被分别发往224.0.0.2(全部

路由器)和224.0.0.1(全部主机),而不是受限的广播地址(255.255.255.255).

224.0.0.4组支持在实现DVMRP的多播路由器之间的通信。

1.以太网多播地址

IP多播的高效实现要求IP充分利用硬件级多播。由于没有硬件级多播。就不得不在网络上广播每一个多播IP数据报。而每台主机

也不得不检查每一个数据报,把哪些不是给它的丢掉。硬件在数据报到达IP层之前,就把没实用的过滤掉了。

为了保证硬件过滤器能正常工作,网络接口必须把IP多播目的地址转换成网络硬件识别的链路级多播地址。在以太网,须要有

一个明白地完毕映射地址的函数,以太网的标准映射适用于不论什么使用802.3寻址方式的网络。

由于以太网支持多种协议,所以要採取措施分配多播地址。避免冲突。IEEE管理以太网多播地址分配。

IEEE把一块以太网多播

地址分给IANA以支持IP多播。块的地址都是以01:00:5e开头。以00:00:5e开头的以太网单播也被分配给IANA,但为将来

使用预留。下图显示了从一个D类IP地址构造出一个以太网多播地址。

《TCP/IP具体解释卷2:实现》笔记--IP多播

2.ether_multi结构

Net/3为每一个以太网接口维护一个该硬件接收的以太网多播地址范围表。

这个表定义了该设备要实现的多播过滤。由于大多数

以太网设备能选择地接收的地址是有限的。所以IP层要准备丢弃那些通过了硬件过滤的数据报。地址范围保存在ether_multi

结构中。

《TCP/IP具体解释卷2:实现》笔记--IP多播

enm_addrlo和enm_addrhi指定须要被接收的以太网多播地址的范围。当enm_addrlo和enm_addrhi同样时。就指定一个以太网

地址。ether_multi的完整列表附在每一个以太网接口的arpcom结构中。下图表示有三个ether_multi结构的LANCE接口。

《TCP/IP具体解释卷2:实现》笔记--IP多播

watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvVE9ERDkxMQ==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center" alt="">

接口已经增加了三个组。可能是224.0.0.1(全部主机)、224.0.0.2(全部路由器)和224.0.1.2(SGI-dogfight)。由于以太网

到IP地址的映射是一对多的,所以无法确定确定的IP地址。接口也可能增加了225.0.0.1,225.0.0.2和225.0.1.2组。

3.以太网多播接收

在Net/3中。也有可能把系统配置成接收全部以太网分组,尽管对IP协议族没实用,但内核的其它协议族可能准备接收这些多播

分组。能够发出下图的ioctl命令,就能够明白地进行多播配置。

《TCP/IP具体解释卷2:实现》笔记--IP多播

这两个命令直接被传给了接口的设备驱动程序(ifp->if_ioctl)

4.in_multi结构

以太网多播数据结构并不专用于IP,它们必须支持全部内核的随意协议族的多播活动。在网络级。IP维护者一个与接口相关

的IP多播组表。

为了实现方便。把这个IP多播表附在与该接口有关的in_ifaddr结构中。

这个结构中包括了该接口的单播地址。除了它们都与

同一个接口相关以外,这个单播地址与所附的多播组表之间没有不论什么关系。

下图的in_multi结构描写叙述了每一个IP多播{接口。组}对。

《TCP/IP具体解释卷2:实现》笔记--IP多播

下图用接口实例le_softc[0]显示了接口,即它的单播地址和它的IP多播表之前的关系。

《TCP/IP具体解释卷2:实现》笔记--IP多播

图中省略了ether_multi结构。

5.ip_moptions结构

传输层通过ip_moptions结构包括的多播选项控制多播输出处理。对每一个输出的数据报,都能够给ip_output传一个ip_moptions

结构。

ip_moptions结构例如以下图所看到的:

《TCP/IP具体解释卷2:实现》笔记--IP多播

imo_multicast_ifp指向的接口对输出的多播数据报进行选路,假设imo_multicast_ifp为空,就通过目的站多播组的默认接口。

imo_multicast_ttl为外出的多播数据报指定初始的IP TTL。默觉得1.

假设imo_multicast_loop为0,就不回送数据报,也不把数据报提交给正在发送的接口,即使该接口是多播组的成员,假设

为1,而且假设正在发送的接口是多播组的成员,就把多播数据报回送给该接口。

最后。整数imo_num_memberships和数组imo_membership维护与该结构相关的{接口。组}对。全部对该表的改变都转告

给IP,由IP在所连到的本地网络上宣布成员的变化。imo_membership数组的每一个入口都是指向一个in_multi结构的指针。

该in_multi结构附在适当接口的in_ifaddr结构上。

6.多播的插口选项

下图显示了几个IP级的插口选项,提供对ip_moptions结构的进程及訪问。

《TCP/IP具体解释卷2:实现》笔记--IP多播

全部的多播选项都由ip_setmoptions和ip_getmoptions函数处理,ip_setmoption主体是一个switch case,对每一个选项

分别调用函数进行处理。

7.多播的TTL值

多播的TTL有两个作用。基本功能是如IP分组一样,限制分组在互联网内的生存期。避免在网络内部无线地循环。第二个

作用是,把分组限制在管理边界所指定的互联网的区域内。

多播路由器还给每一个接口关联一个TTL阈值。限制在该接口上的多播传输。一个要在该接口上传输的分组必须具有大于或

等于该接口阈值的TTL。所以多播分组可能会在它的TTL到0之前就被丢弃了。

阈值时管理员在配置多播路由器时分配的,这些值确定了多播分组的辖域。

下图显示了多种应用程序的推荐TTL值和推荐

的阈值。

《TCP/IP具体解释卷2:实现》笔记--IP多播

8.增加一个IP多播组

除了内核自己主动增加的IP全部主机外。其它组成员是由进程明白发出请求产生的。

增加(或离开)多播组选项比其它选项很多其它

使用。必须改动接口的in_multi表以及其它链路层多播结构,如ether_multi。

当optname是IP_ADDMEMBERSHIP时,mbuf中的数据例如以下图所看到的的ip_mreq:

《TCP/IP具体解释卷2:实现》笔记--IP多播

watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvVE9ERDkxMQ==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center" alt="">

ip_mreq结构指定{接口。组}对表示成员的变化。

下图显示了增加与离开我们的以太网接口样例相关的多播组时,所调用的函数。

《TCP/IP具体解释卷2:实现》笔记--IP多播

watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvVE9ERDkxMQ==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center" alt="">

对于IP_ADD_MEMBERSHIP选项,ip_setmoptions的大致处理流程例如以下:

1.验证。对传入的參数进行检查。

2.找到接口。假设mreq中的imr_interface是INADDR_ANY,则必须找到指定组的默认接口,由rtalloc函数为多播组找到一个

路由器。假设imr_interface不是INADDR_ANY。则请求一个明白的接口。依据提供的地址搜索接口。

3.已经是成员了?检查imo_membership数组,看看所选接口是否已经是请求组的成员。假设找到一个匹配,或者成员已满,

则终止对这个选项的处理。

4.增加多播组。调用in_addrmulti函数增加多播组。

8.1.in_addrmulti函数

in_addrmulti和in_delmulti函数维护接口已添加多播组的表。添加请求或者在接口表中添加一个新的in_multi结构,或者添加

对某个已有结构的引用次数。(该函数是在协议层面上进行增加多播组的操作)

函数的大概处理流程例如以下:

1.假设已经是一个成员。则查找到该成员相应的in_multi结构,更新引用计数后返回。

2.假设接口还不是成员,则in_addrmulti分配并初始化一个新的in_multi结构,并将该结构插到接口的in_ifaddr结构中ia_multiaddrs

表的前端。

3.更新接口,通告变化。假设接口驱动程序已经定义了一个if_ioctl函数,则调用该函数。

最后,in_addrmulti调用igmp_joingroup,

把成员变化信息传播给其它主机和路由器。

8.2.leioctl函数:SIOCADDMULTI和SIOCDELMULTI

对于LANCE以太网接口,if_ioctl函数指针指向leioctl函数。

在leioctl函数中,对于SIOCADDMULTI和SIOCDELMULTI选项。

分别调用ether_addmulti函数和ether_delmulti函数。

8.3.ether_addmulti函数

ether_addmulti函数是在接口层对增加多播组进行操作。

这个函数把IP D类地址映射到合适的以太网地址上,并更新ether_multi

表。函数的大概处理流程例如以下:

1.初始化地址范围。ether_addmulti初始化addrlo和addrhi中的多播地址范围。假设所请求的地址来自AF_UNSPEC族,

ether_addmulti假定该地址时一个明白的以太网多播地址,并把它拷贝到addrlo和addrhi中。假设地址属于AF_INET族,而且

是INADDR_ANY,ether_addmulti把addrlo初始化成ehter_ipmulticast_min。把addrhi初始化成ether_ipmulticast_max。

这两个以太地址常量定义为:

《TCP/IP具体解释卷2:实现》笔记--IP多播

watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvVE9ERDkxMQ==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center" alt="">

2.已经在接收。

ether_addmulti检查高地址和低地址的多播比特位。保证它们是真正的以太网多播地址。然后确定硬件是否已经

对指定的地址開始监听。假设是,则添加匹配ether_multi结构中的引用计数(enm_refcount)。

3.更新ether_multi表。

假设是一个新的地址范围,则分配并初始化一个新的ether_multi结构,把它链到接口arpcom结构中的

ac_multiaddrs表上,最后函数返回,依据返回值。设备驱动程序知道多播表被改变了。必须更新硬件接收过滤器。

下图显示了LANCE以太网接口增加主机组后,ip_moptions、in_multi和ether_multi结构之间的关系。

《TCP/IP具体解释卷2:实现》笔记--IP多播

watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvVE9ERDkxMQ==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center" alt="">

9.离开一个IP多播组

通常情况下。离开一个多播组的步骤时增加一个多播组的步骤的反序。更新ip_moptions结构中的成员表、IP接口的in_multi表

和设备的ether_multi表。

我们回到ip_setmoptions中的IP_DROP_MEMBERSHIP情况语句。语句中用请求的{接口。组}对组成员表中寻找一个in_multi

结构。假设找到。则调用in_delmulti更新in_multi表,然后调用igmp_leavegroup(不做不论什么操作)。最后,调用if_ioctl函数指针指向

的ether_delmulti函数,删除找到的ether_multi结构。

10.多播输入处理:ipintr函数

ether_input检測到达的以太网多播分组,在把一个IP分组放到IP输入队列之前(ipintrq),把mbuf首部的M_MCAST标志位置位。

ipintr函数按顺序处理每一个分组。

在ipintr函数内,用来确定分组是寻址到本地网络还是应该被转发。

假设目的地址是一个多播组。而且系统被配置成IP多播路由器。就把分组传给ip_mforward。

11.多播输出处理:ip_output函数

ip_output对多播的大概处理流程例如以下:

1.建议默认值。把mbuf中的M_MCAST置位。并把目的地址设置为终于目的地址。

假设传递了一个ip_moptions结构,则对应地

改变ip_ttl和ifp。

否则ip_ttl设置为1,避免多播分组达到某个远程网络。

2.选择源地址。假设没有指定源地址。则找到与输出接口相关的单播地址,作为src ip。与单播分组不同,假设系统被配置成一个

多播路由器,则必须在一个以上的接口上输出多播分组。即使系统不是一个多播路由器。输出的接口也可能是目的多播组的一个

成员,也会须要接收该分组。最后,我们须要考虑一下多播环回策略和环回接口本身。共同拥有三个问题:

3.是否环回?假设输出接口是目的多播组成员。则分组被ip_mloopback放到输出接口上排队,等待输入。

4.是否转发?假设分组不是环回的,但系统被配置成一个多播路由器。而且分组符合转发的条件,则ip_mforward向其它多播接口

分发该分组的备份。

5.是否发送?假设TTL为0或者输出接口是环回接口。则丢弃该分组。

6.发送分组。

分组从物理上在输出接口上被发送。