上一篇我们讲到,因为my_inet是系统中第二个加载的IPv4模块,所以网络设备接口早已完成了加入IGMP_ALL_HOST组的操作,my_inet只是简单增加引用计数和源过滤计数,下面我们来看看,第一个加载的IPv4模块(即内核原有的TCP/IP协议栈模块)是如何把网络设备接口加入IGMP_ALL_HOST组的。 在myip_mc_inc_group函数中,首先检查in_device->mc_list列表中已加入的组播组,看本接口是否已经加入了IGMP_ALL_HOST组,结果当然是没有。则,首先创建一个新的结构体struct ip_mc_list *im,初始化其成员值,设成员multiaddr为组播地址224.0.0.1,sf_mode为MCAST_EXCLUDE,sfcount[MCAST_EXCLUDE]为1,sources为NULL,表示使用一个源过滤机制,该机制不过滤任何组播源。成员loaded为0,表示该组播组尚未被载入(稍后将看到载入的操作)。初始化完成后,将这个新的组播组加入到mc_list链表的表头。 前面讲到过,mc_tomb也是in_device的一个成员,也表示一个组播组列表,这个列表中的组应该是不活跃的(当前不在使用的,具体留待以后分析),新的组加入到mc_list成功后,还要到这个列表中查找,看是否也存在于这个列表中,如果存在,要删除,因为该组当前是活跃的。 最后,调用myigmp_group_added完成真正的加入组播组的操作,对于IGMP_ALL_HOST这个组来讲,该函数做的事情相对比较少,它检查loaded成员,发现为0,则调用myip_mc_filter_add,加入一个网络设备级的组播地址。也就是说,代表网络设备接口的结构体struct net_device有一个成员mc_list,它是一个链表,每个结点代表一个组播组的mac地址。与in_device的mc_list中的组播IP地址对应。loaded为0时,我们要做的事情就是把IP地址224.0.0.1映射成一个mac地址加到net_device的mc_list链表中去,然后把loaded置1,该成员的结点定义如下: struct dev_mc_list { struct dev_mc_list *next; __u8 dmi_addr[MAX_ADDR_LEN]; unsigned char dmi_addrlen; int dmi_users; int dmi_gusers; }; dmi_addr是mac地址,dmi_addrlen是地址长度,dmi_users是引用计数。添加完成后,net_device的成员mc_count相应的加1。 下面我们来看看组播IP地址是如何被映射成组播mac地址的。 一个mac地址总共有6字节,48位,被分成两段:前3字节和后3字节,前3字节用于标识网卡的制造厂商,其中第40位(第一字节的最低位)用于标识组播,所以在网卡的mac地址中必须置0,后3字节是厂商内部使用的序列号。一个组播IP地址映射成mac地址的规则是:前三字节强制置01:00:5E,后3字节中,第23位置0,0-22位放入IP地址的0-23位。
阅读(1280) | 评论(0) | 转发(0) |