最近在用ns2帮别人做移动自组网aodv协议的改进仿真实验,学习了路由仿真方面的不少知识,顺手记录下来。
ns2的安装
查阅网上资料发现ns2可以在cygwin上安装,为了省事就用cygwin安装了ns-2.35。具体的安装步骤可以参考下面的参考资料。
AODV协议的改进
ns2安装好后,所有的协议都存在ns-2.35目录下面打开aodv目录,里面就是aodv协议相关的代码了,其中aodv.cc是协议的主要代码,代码中关键的地方都有英文注释还是比较好理解的。
//收到的数据包都会先进入这个方法
void AODV::recv(Packet *p, Handler*) {
struct hdr_cmn *ch = HDR_CMN(p);
struct hdr_ip *ih = HDR_IP(p);
assert(initialized());
//assert(p->incoming == 0);
// XXXXX NOTE: use of incoming flag has been depracated; In order to track direction of pkt flow, direction_ in hdr_cmn is used instead. see packet.h for details.
//如果是AODV的数据包,进入recvAODV方法
if(ch->ptype() == PT_AODV) {
ih->ttl_ -= 1;
recvAODV(p);
return;
}
/*
* Must be a packet I'm originating...
*/
if((ih->saddr() == index) && (ch->num_forwards() == 0)) {
/*
* Add the IP Header.
* TCP adds the IP header too, so to avoid setting it twice, we check if
* this packet is not a TCP or ACK segment.
*/
if (ch->ptype() != PT_TCP && ch->ptype() != PT_ACK) {
ch->size() += IP_HDR_LEN;
}
// Added by Parag Dadhania && John Novatnack to handle broadcasting
if ( (u_int32_t)ih->daddr() != IP_BROADCAST) {
ih->ttl_ = NETWORK_DIAMETER;
}
}
/*
* I received a packet that I sent. Probably
* a routing loop.
*/
else if(ih->saddr() == index) {
drop(p, DROP_RTR_ROUTE_LOOP);
return;
}
/*
* Packet I'm forwarding...
*/
else {
/*
* Check the TTL. If it is zero, then discard.
*/
if(--ih->ttl_ == 0) {
drop(p, DROP_RTR_TTL);
return;
}
}
// Added by Parag Dadhania && John Novatnack to handle broadcasting
if ( (u_int32_t)ih->daddr() != IP_BROADCAST)
rt_resolve(p);
else
forward((aodv_rt_entry*) 0, p, NO_DELAY);
}
//根据aodv包的类型不同,进入不同的方法
void AODV::recvAODV(Packet *p) {
struct hdr_aodv *ah = HDR_AODV(p);
assert(HDR_IP (p)->sport() == RT_PORT);
assert(HDR_IP (p)->dport() == RT_PORT);
/*
* Incoming Packets.
*/
switch(ah->ah_type) {
case AODVTYPE_RREQ:
recvRequest(p);
break;
case AODVTYPE_RREP:
recvReply(p);
break;
case AODVTYPE_RERR:
recvError(p);
break;
case AODVTYPE_HELLO:
recvHello(p);
break;
default:
fprintf(stderr, "Invalid AODV type (%x)\n", ah->ah_type);
exit(1);
}
}
recvRequest、recvReply、recvError、recvHello对应的就是收到控制包后不同的处理方法。与之对应的send***就是发送数据包时对应的方法。
添加ns2协议
一般不建议直接修改原始的aodv协议,可以将修改的协议作为新协议添加进ns2中,具体步骤如下:
- common/packet.h
– 添加static const packet_t PT_XXX = XX;
注意修改最后PT_NTYPE的值
– 添加type==PT_XXX ||
– 添加name_[PT_XXX] = 'xxx'
- trace/cmu-trace.h
– 添加void format_caodv(Packet *p, int offset)
方法 - trace/cmu-trace.cc
– 对应aodv的头文件,添加新协议的头文件
– 添加CMUTrace::format_xxx(Packet *p , int offest)
函数,内容参考format_aodv
函数的
– 在void CMUTrace::format(Packet* p, const char *why)
函数中参照aodv的写法添加case PT_XXX: format_xxx(p, offset); break;
- queue/priqueue.cc
– 在case PT_AODV
下面添加case PT_XXX:
- tcl/lib/ns-packet.tcl
– 搜索AODV,然后在AODV的下面添加XXX,表示声明。 tcl/lib/ns-lib.tcl
– 添加XXX{set ragent [$self create-xxx-agent $node]}
– 添加
Simulator instproc create-xxx-agent { node } {
set ragent [new Agent/XXX[$node node-addr]]
$self at 0.0 "$ragent start"
$node set ragent_ $ragent
return $ragent
}tcl/lib/ns-mobilenode.tcl
– 为了设置协议的混杂模式,添加
# Special processing for XXX
set xxxonly [string first "XXX" [$agent info class]]
if {$xxxonly != -1 } {
$agent if-queue [$self set ifq_(0)] ;# ifq between LL and MAC
}
协议修改好后,需要对ns2进行重新编译,cd进入ns-2.35目录,输入:make clean&&make
实验仿真
编译成功后,就要进行仿真实验了,一般采用ns-2.35/indep-utils/cmu-scen-gen/目录下的cbrgen.tcl来生成数据流,采用setdest来生成拓扑关系。具体用法如下:
ns cbrgen.tcl [ -type cbr | tcp ] [ -nn nodes ] [ -seed seed ] [-mc connections ] [ -rate rate ]
各参数定义如下:
- -type: 数据流类型。
- -nn:节点数目。
- -seed: 指定随机种子。
- -mc: 节点间的最大连接数。
- -rate: 数据流发送速率。
./setdest -v<2> -n <nodes> -s <speed_type> -m <min_speed> -M <max_speed> -t <simulation_time> -P <pause_type> -p <pause_time> -x <max_X> -y <max_Y>
各参数定义如下:
- -v: 指定 setdest 的版本。
- -n: 场景中总的节点数目。
- -p: 节点在运动到达某一目的点的暂停时间, 若设置为 0 则代表不停留。
- -s: 节点速度分布情况, uniform 代表均匀分布, normal 代表正态分布。
- -m: 节点移动的最小速率。
- -M: 节点移动的最大速率。
- -P: 节点暂停时间类型。
- -t: 网络仿真的持续时间,单位为 s。
- -x: 仿真区域的长度,单位: m。
-y: 仿真区域的宽度,单位: m。
仿真需要写tcl文件,可以仿照aodv.tcl的例子写,如果需要开启能量模型,需要在tcl文件中配置能量节点和初始参数。
tcl运行完后会生成“.tr”为后缀的trace文件,trace文件包含了仿真过程中的所有分组调度事件,并按时间排序,具体的trace文件格式可以参照下面的参考文献,trace文件的分析一般采用gawk来提取并统计出仿真数据,最后使用gnuplot画出图形进行对比。具体gawk的使用及各项网络性能指标的公式参看下面的参考资料。
最后,用gnuplot把gawk分析出来的数据画出来就行了,具体方法参看参考资料。