MFlood源码学习

参考资料:http://blog.csdn.net/leo115/article/details/7784349

徐雷鸣:NS与网络模拟

MFlood类中有recv函数

先检测是否是自己生成的,如果是自己发的,且转发的次数为0,那么就是自己生成的。

ip header的source addr,index_是自己的ip地址,比较这两个可以判断是否自己发的

common header中的num_forwards可以得到转发的次数

如果是自己生成的将common header的size加上IP包的长度,将ip header的ttl设为最大,将flood的seq_加1,然后转发包。

然后检测是否是路由环路,如果是自己发的,且转发次数不为0,那么就是一个路由环路,丢弃

然后检测ttl是否为0,如果是丢弃

如果不是上面所有的情况,那么解析包,即寻找下一跳地址。

// Packet Reception Routines
void
MFlood::recv(Packet *p, Handler*) {
	struct hdr_cmn *ch = HDR_CMN(p);
	struct hdr_ip *ih = HDR_IP(p);
	struct hdr_mflood *fh = HDR_MFLOOD(p);
	assert(initialized());

	if((ih->saddr() == index_) && (ch->num_forwards() == 0)) {	// Must be a packet I'm originating...		
		ch->size() += IP_HDR_LEN;		// Add the IP Header
		ih->ttl_ = NETWORK_DIAMETER;
		fh->seq_ = myseq_++;			
		forward((MFlood_RTEntry*)1,p,0);		
		return;
	} else if(ih->saddr() == index_) {	// I received a packet that I sent.  Probably a routing loop.
		drop(p, DROP_RTR_ROUTE_LOOP);
		return;
	} else {		// Packet I'm forwarding...
		if(--ih->ttl_ == 0) {	// Check the TTL.  If it is zero, then discard.
			drop(p, DROP_RTR_TTL);
	 		return;
		}
	}

	rt_resolve(p);
}

路由表解析,先检查路由表项中有没有这个源地址路由表项里不是目的地址吗?因为是扩散法,见计算机网络书,或下面对seqno的解释),如果没有,那么需要创建这个路由表项,并将其插入路由表的路由表项链表,路由表是表(程序中实际实现是通过链表实现,而不是二维数组什么的,因为二维数组删除添加什么的不灵活),路由表项是路由表的元素,Entry是表项的意思。添加完路由表项之后,再转发。

// Route Handling Functions
void
MFlood::rt_resolve(Packet *p) {
	struct hdr_cmn *ch = HDR_CMN(p);
	struct hdr_ip *ih = HDR_IP(p);
	struct hdr_mflood *fh = HDR_MFLOOD(p);
	MFlood_RTEntry* rt;

	rt = rtable_.rt_lookup(ih->saddr());
	if(rt == NULL) {
		rt = new MFlood_RTEntry(ih->saddr(), fh->seq_);

		LIST_INSERT_HEAD(&rtable_.rthead,rt,rt_link);		
	
		//printf("%.8f %d,no uptarget,\n",NOW,index_);
		forward(rt,p,FORWARD_DELAY);
		
//printf("%.8f %d,no rt,so forward.rt_seq:%d,pkt seq:%d\n",NOW,index_,rt->max_seqno,fh->seq_);
rtable_.rt_print();		
		
	}
//	else if(rt->seq_ < fh->seq_ )
	else if(rt->isNewSeq(fh->seq_) )
	{

如果路由表项中有这个源地址,再检查seq是否重复,使用了max_seqno, min_seqno,在一个数组中存储已经接收到的seqno。如果不重复,那么转发,同时将seqno添加进路由表项中。

计算机网络书中对flood扩散法的说明:每个源路由器(在这里为源节点,因为WSN中节点也充当路由器的角色)对从自己生成的分组维护一个序列号seqno,中间的路由器针对每个源地址都存储一个seqno表,从而判断是否是重复包。所以,路由表项中的地址是源地址,而不是普通路由算法的目的地址。
	else if(rt->isNewSeq(fh->seq_) )
	{
		//printf("%.8f %d,no uptarget,\n",NOW,index_);
		forward(rt, p, FORWARD_DELAY);
		
//		rt->seq_ = fh->seq_;
		rt->addSeq(fh->seq_);

//printf("%.8f %d,rt seq too small,so forward,rt_seq:%d,packet seq:%d.\n",NOW,index_,rt->max_seqno,fh->seq_);	
rtable_.rt_print();		
	}
	else
	{
		drop(p, "LOWSEQ");
	}
}


下面解释一下整个路由表的实现,发现自己背离了扩散法的原理去读代码,结果读的一头雾水,当重新了解了一下扩散法的原理之后,代码也就清晰了,汗颜啊!而且,徐雷鸣的书中有专门介绍MFlood的,里面也讲的比较清楚,早看的话,就能少走些弯路了,不过自己想出来的也挺有成就感的:

MFlood类下会有路由表rtable_,而路由表类下又有一个路由表链表(由路由表项元素组成的链表)rthead,而路由表项类下会有变量src_,这就是源地址,每个表项对应一个源地址,对应一个序列号seqno数组rt_seqnos[REM_SEQ_COUNT]。

 

即每个路由表项下会有一个源地址,一个序列号数组,这就是扩散法的路由表需要的内容,而普通路由算法的话,应该会有目的地址,下一跳地址等。

 

另外为了防止路由表项无限扩大,设置了max_seqno变量(计算机网络书中讲到),如果收到的分组的源地址对应的seqno大于max,那么肯定是新的;如果小于max,mflood中还设置了一个min_seqno,用于丢弃太久之前的包,这里可能seqno回卷的话就不对了啊,这里每太想明白???

关于路由表项链表的操作也没太看明白,下面这个链表表项第二项是上一个下一个元素的地址,链表不是上一个元素和下一个元素的指针吗???

#define LIST_ENTRY(type)                                          \
struct {                                                    \
       type*le_next;     /* next element */                   \
       type**le_prev;   /* address of previous nextelement */       \
}

 

一开始一直看不明白下面是什么意思,怎么还把基类的构造函数搬出来了,C++继承那块一直没仔细看,原来继承不会继承基类的构造和析构函数,在派生类构造函数时,也要执行基类的构造函数,当派生类中内嵌其他类的时候,也要将这些类构造。

MFlood::MFlood(nsaddr_t id) : Agent(PT_MFLOOD) {
	index_ = id;
	logtarget = 0;
	myseq_ = 0;
}
  徐雷鸣书中对C++和Tcl之间关系的解释:

MFlood源码学习_第1张图片

你可能感兴趣的:(MFlood源码学习)