NS2路由协议和数据转发

来源:互联网 发布:ubuntu进桌面后无unity 编辑:程序博客网 时间:2024/06/06 08:59

今天刚在netforum上看到一个帖子,讨论的是NS2路由协议和数据转发,转载下:

 

我再写一次,看能不能发上来!在ns manual中有一章是介绍classifier的,这个classifier就是一个节点的入口,功能就是利用路由表,根据一定的规则将收到的数据包进行转发,单播路由中默认的分类器是DestHashClassifier,就是根据数据包的目的地址来转发。可以看出来,这个里面和路由协议是没有关系的。但是又不是真的没有关系,路由表就是路由协议形成的。路由协议其实也是在每个节点上有一个路由agent,任何节点上的agent都是有端口的,所以这个时候可以把路由agent看作是tcp层的(事实上也是),各个路由agent之间进行通信,通信的方式和我们的tcp层的agent的通信方式是一样的。所以这个agent肯定看不到本节点上其他agent的数据,所以想在路由协议里处理节点的数据包(非路由包)是不可能的事情。

void Classifier::recv(Packet* p, Handler*)
{
NsObject* node;
int cl = classify(p);
if (cl < 0 || cl >= nslot_ || (node = slot_[cl]) == 0) {
Tcl::instance().evalf("%s no-slot %d", name(), cl);
Packet::free(p);
return;
}
node->recv(p);
}

看见没有,这个是classifier的recv函数,就是接受到一个包后,根据一定的规则(classify)来查询路由表(一个表项就是一个slot),然后再用相应的节点的recv函数接收(就是把数据转发出去了)。

 

这也就是说明了一个问题,如果想要做一个能处理数据报的上层overlay,那么就不能做成agent的形式,因为agent之间是不透明,overlay agent是无法看到tcp or udp agent所产生的数据报,也就无从进行处理,这就很有意思了,应该怎么做呢……

 

08/25

也不见得就一定是不行,难道真的不能让一个agent接收其他agent的数据吗?

不管怎么说要先明白一个节点接收和处理数据包的流程,NS Manual第五章描述了节点和转发的一些细节。有个图很有意思。


 

 

讲述了数据包进入节点的流程:

首先对数据包进行处理的模块是entry,entry本身只是一个标签变量而非是像classifier一样的实例变量。entry的作用,很多资料写的不尽不实,manual的说法是,entry返回的是当前节点的入口地址。对于单播节点而言,这个变量是一个用来检查目的地址高位字段的分类器。

Tcl对象之一:地址分类器(address classifier),用来判断分组的目标地址,/ns-2.27/classifier/classifier-addr.{h/cc};
Tcl对象之二:端口分类器(port classifier),用来判断分组的目标Agent,/ns-2.27/classifier/classifier-port.{ h/cc}。


个人的观点是,当一个节点收到packet时,先由Addr_classifier来判断目的地址,如果packet的dst_addr不是本节点的address,则查询路由表,将packet转发到相应的link上,如果dst_addr与本节点address相同,则将packet交由port_classifier判断packet所用的端口,然后转交给使用相应端口的agent。

如果实际的处理流程是这样的话,那就很麻烦了,那就意味,如果使用agent来设计overlay system,那么这个overlay agent是无法接收到packet的,因为packet的dst_addr是end的address,而不是安装了overlay system的中间节点的address,那么这个中间节点收到packet之后,他会将packet转发到相应的link上而不是交给上层的agent,所以overlay agent是收不到packet的。

 

08/26

有一个想法,既然packet在到达后会由Addr_Classifier来进行分类并进行对应的处理,那么能不能修改Addr_Classifier文件,判断如果packet到达的当前节点是overlay的节点,则把packet递交给Port_Classifier,然后交给overlay agent进行处理,最后再发送出去呢?

如果idea是可行的,那么还有两个问题要解决:

1. NS2本身并没有提供查询packet所到达的节点的address或者id的功能,如何添加这个功能?这个也许有帮助(如何测试呢?)

我有一点明白他是怎么获得当前节点地址的了,但是仍然不确信这个方法是否正确,或者能否及时的获得当前节点的id。这个方法其实是通过调用trace的一些特点来变相的来获取当前节点的id。NS2的trace本身会跟踪所有节点上的所有事件,当然其中包括了接收和发送packet,根据下面几个贴的说法:

Trace文件记录的是每个结点的哪个层(路由层、代理层等)发送或接收包的历史记录。也就是说,每当一个结点要发送或接收到一个包时,Trace文件就会为其生成一条对应的记录。

在C++实现的Trace/cmu-trace.cc中,有一个recv函数,每当结点接收或发送包时,都会调用Trace的recv函数,为其写记录。
trace会检查src_和dst_,这里的两个地址应该是当前这个动作的src和dst地址,src就应该是当前节点的地址。不过就像下面的回复里说的,在trace事件被记录之前,这个方法应该是得不到id的。我猜。不过这些还需证实。(09/02)
 

Manual上是这么说的,“内部状态src_ 和dst_用来标识跟踪输出,他和包头中相应域的名字各自独立。recv()仅仅使用源,目的和特殊的跟踪类型字符来格式化一个跟踪入口。dump()函数把格式化了的跟踪入口写到域channel_相关联的I/O句柄。format函数实际规定了跟踪的文件格式。”

 

2. 如何编写agent,还有制定packet递交的端口?


 

09/02


继续拼凑有用的资料
Windows下NS2-2.33完全安装步骤
在NS2中跟踪变量的一个方法:
不是我原创的,是我在改xcp中经常使用的trace变量的方法,很习惯于用他,以至于在tcp中用不了,我都有点手足无措了。
我以在tcp 中添加为例
在tcp.h中添加void trace_var(char * var_name, double var);
在tcp.cc中添加
void TcpAgent::trace_var(char * var_name, double var)
{
    char wrk[500];
    if (channel_) {
        int n;
        sprintf(wrk, "%g x x x x %s %g",Scheduler::instance().clock(),var_name, var);
        n = strlen(wrk);
        wrk[n] = '/n';
        wrk[n+1] = 0;
        (void)Tcl_Write(channel_, wrk, n+1);
    }
}

当你想在某个地方跟踪变量的变化是trace_var(”aaa“,cwnd_);
然后在tcl文件中tcp_ attach-trace [set ftracetcp$id_]
就ok了

有关ns2的事件跟踪

ns2中限制Trace文件的输出

http://www.netforum.com.cn/viewthread.php?tid=3580&extra=&page=1
调用了的。

你可能不是很清楚调用的机制。

举个例子Myagent Mycommand(假如这是个tcl脚本里的语句)

解释器先在tcl脚本定义的类Myagent中找Mycommand这个成员函数,如果找到就执行。

如果没有找到,解释器就直接将命令变为Myagent cmd Mycommand,cmd这个函数就会调用c++中的command函数,然后将cmd Mycommand作为参数传递进去。就像上面楼主的例子中那样调用了(为什么从argv[1]开始算?argv[0]为“cmd”)

09/22/2010
This is kind of insteresting. 我用gdb跟踪了整个ns2的运行过程,发现确实是比较复杂,互相的调用还是有很多看不太懂的地方。但是有一点应该是能够肯定的,那就是上面所讲的方法应该是可行的,还没有确实的论证过。那是下一步的事情。应该是把对packet的修改加到 Trace::recv()里面: