《TCP/IP具体解释卷2:实现》笔记--IP多播
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多播组表。
下图
仅仅给出了一些知名的多播组。
全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地址构造出一个以太网多播地址。
2.ether_multi结构
Net/3为每一个以太网接口维护一个该硬件接收的以太网多播地址范围表。
这个表定义了该设备要实现的多播过滤。由于大多数
以太网设备能选择地接收的地址是有限的。所以IP层要准备丢弃那些通过了硬件过滤的数据报。地址范围保存在ether_multi
结构中。
enm_addrlo和enm_addrhi指定须要被接收的以太网多播地址的范围。当enm_addrlo和enm_addrhi同样时。就指定一个以太网
地址。ether_multi的完整列表附在每一个以太网接口的arpcom结构中。下图表示有三个ether_multi结构的LANCE接口。
接口已经增加了三个组。可能是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命令,就能够明白地进行多播配置。
这两个命令直接被传给了接口的设备驱动程序(ifp->if_ioctl)
4.in_multi结构
以太网多播数据结构并不专用于IP,它们必须支持全部内核的随意协议族的多播活动。在网络级。IP维护者一个与接口相关
的IP多播组表。
为了实现方便。把这个IP多播表附在与该接口有关的in_ifaddr结构中。
这个结构中包括了该接口的单播地址。除了它们都与
同一个接口相关以外,这个单播地址与所附的多播组表之间没有不论什么关系。
下图的in_multi结构描写叙述了每一个IP多播{接口。组}对。
下图用接口实例le_softc[0]显示了接口,即它的单播地址和它的IP多播表之前的关系。
图中省略了ether_multi结构。
5.ip_moptions结构
传输层通过ip_moptions结构包括的多播选项控制多播输出处理。对每一个输出的数据报,都能够给ip_output传一个ip_moptions
结构。
ip_moptions结构例如以下图所看到的:
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结构的进程及訪问。
全部的多播选项都由ip_setmoptions和ip_getmoptions函数处理,ip_setmoption主体是一个switch case,对每一个选项
分别调用函数进行处理。
7.多播的TTL值
多播的TTL有两个作用。基本功能是如IP分组一样,限制分组在互联网内的生存期。避免在网络内部无线地循环。第二个
作用是,把分组限制在管理边界所指定的互联网的区域内。
多播路由器还给每一个接口关联一个TTL阈值。限制在该接口上的多播传输。一个要在该接口上传输的分组必须具有大于或
等于该接口阈值的TTL。所以多播分组可能会在它的TTL到0之前就被丢弃了。
阈值时管理员在配置多播路由器时分配的,这些值确定了多播分组的辖域。
下图显示了多种应用程序的推荐TTL值和推荐
的阈值。
8.增加一个IP多播组
除了内核自己主动增加的IP全部主机外。其它组成员是由进程明白发出请求产生的。
增加(或离开)多播组选项比其它选项很多其它
使用。必须改动接口的in_multi表以及其它链路层多播结构,如ether_multi。
当optname是IP_ADDMEMBERSHIP时,mbuf中的数据例如以下图所看到的的ip_mreq:
ip_mreq结构指定{接口。组}对表示成员的变化。
下图显示了增加与离开我们的以太网接口样例相关的多播组时,所调用的函数。
对于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。
这两个以太地址常量定义为:
↓
2.已经在接收。
ether_addmulti检查高地址和低地址的多播比特位。保证它们是真正的以太网多播地址。然后确定硬件是否已经
对指定的地址開始监听。假设是,则添加匹配ether_multi结构中的引用计数(enm_refcount)。
↓
3.更新ether_multi表。
假设是一个新的地址范围,则分配并初始化一个新的ether_multi结构,把它链到接口arpcom结构中的
ac_multiaddrs表上,最后函数返回,依据返回值。设备驱动程序知道多播表被改变了。必须更新硬件接收过滤器。
下图显示了LANCE以太网接口增加主机组后,ip_moptions、in_multi和ether_multi结构之间的关系。
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.发送分组。
分组从物理上在输出接口上被发送。