我们知道在内核中用结构体struct
net_device标识一个网络设备接口,该结构体有一个成员指针ip_ptr,它是留给IPv4协议用于填充协议相关的一些数据的。IPv4协议的模
块将其指向一个结构体struct
in_device,该结构体含有很多协议相关的数据,比如配置在这个网络设备接口上的所有的IPv4的地址,该网络设备接口接受的组播地址等,下面是其
完整的定义:
struct in_device
{
struct net_device *dev;
atomic_t refcnt;
int dead;
struct in_ifaddr *ifa_list; //IP地址列表
rwlock_t mc_list_lock;
struct ip_mc_list *mc_list; //IP组播过滤列表。
spinlock_t mc_tomb_lock; //下面都是组播相关数据。
struct ip_mc_list *mc_tomb;
unsigned long mr_v1_seen;
unsigned long mr_v2_seen;
unsigned long mr_maxdelay;
unsigned char mr_qrv;
unsigned char mr_gq_running;
unsigned char mr_ifc_count;
struct timer_list mr_gq_timer; /* general query timer */
struct timer_list mr_ifc_timer; /* interface change timer */
struct neigh_parms *arp_parms;
struct ipv4_devconf cnf;
struct rcu_head rcu_head;
};
我们暂时还无法完全理解这个结构体,目前只需关注的是mc_list成员,这是关于组播的一个最为关键的数据结构。mc_list是一个链表,链表的一个
结点代表一个组播地址(也就是一个多播组的组号),代表这个网络设备接口已经加入了这个组播组,需要接收来自这个组的数据报。下面是该节点的结构体定义:
struct ip_mc_list
{
struct in_device *interface;
unsigned long multiaddr;
struct ip_sf_list *sources;
struct ip_sf_list *tomb;
unsigned int sfmode;
unsigned long sfcount[2];
struct ip_mc_list *next;
struct timer_list timer;
int users;
atomic_t refcnt;
spinlock_t lock;
char tm_running;
char reporter;
char unsolicit_count;
char loaded;
unsigned char gsquery;
unsigned char crcount;
};
同样,我们把其中的大部分成员留待以后理解。multiaddr就是组播地址,sources和tomb是关于组播源地址的一个列表,sfmode和
sfcount是过滤参数,也就是说,该网络设备接口虽然加入了某个组播组,但对某些主机向该组发的数据报不接收,或者只接收某个主机发向该组的数据报,
这就要对组播源进行过滤。
关于D类地址的常识,这里不再介绍,可参考相关书籍。
下面介绍一个特殊的组播地址224.0.0.1,它标识子网中的所有主机,同一个子网内具有组播功能的主机都属于这个组。我们的my_inet模块在初始
化时,myinetdev_event函数收到网络设备接口启动(NETDEV_UP)的消息后,调用myip_mc_up启动组播功能。
启动组播功能的第一件事便是把本机加入到这个特殊的组播组IGMP_ALL_HOSTS(即224.0.0.1),调用
myip_mc_inc_group函数完成加入动作。因为我们的my_inet模块是作为系统中的第二个IPv4模块,在系统正常运行后被加载的,所
以,网络设备接口早已完成了加入该组播组的操作。my_inet模块的加入动作是只是简单地将成员users加1,然后调用
myip_mc_add_src函数加入组播源过滤。
IGMP_ALL_HOSTS组的sources为NULL,sfmode为MCAST_EXCLUDE(过滤掉sources中列出的所有源),所以结
果是不过滤任何组播源。myip_mc_add_src函数中,将sfcount[MCAST_EXCLUDE]的值加1,表示新增一个过滤机制。
阅读(1115) | 评论(0) | 转发(1) |