NS2中无线网络模拟之三(AODV路由分析2)

在分析AODV路由协议时,首先要明白,AODV只是一个路由协议,它的本质工作就是去管理路由表,所有的更新工作只是在实现对路由表的增、删、改、查工作。下面,我们继续之前的分析。

首先,我选择的切入点当然是从路由请求开始,分析源码,看它如何实现,关键代码贴出来分析:

我们从recv函数来分析

主函数

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.

 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);
}<span style="color:#ff0000;">
</span>


分析1、

 if(ch->ptype() == PT_AODV) {
   ih->ttl_ -= 1;
   recvAODV(p);
   return;
 }
如果本节点收到一个数据包,这个数据包首先类型是PT_AODV,而且不是由我自己产生的,那么调用recvAodv(p)函数,并且给其TTL-1.

调用函数

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);
 }

}
在recvAODV(Packet p)函数中,首先获取到hdr_aodv的包头指针,然后根据IP头判断源端口与目的端口是否相同。这个是因为我们的AODV继承自Agent,作为一个代理,所以,保证目的端口要一致。接下来,利用switch来判断接收到的数据包是什么类型,然后调用相应的函数。这几个函数一会儿再来分析,先回到主线程。因为现在我们知道了我们的AODV路由协议基本函数是在这里调用的。

分析2、

回到主函数接下来,我们再来分析,如果这个数据包是我自己生成的(根据节点原理图,就是这个数据包我的上层TCP传下来的,如蓝色代码,

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;
  }
}
通过查看TCP的源码我们会发现,TCP中有一个headersize()函数,这个函数返回tcpip_base_hdr_size_变量的值,即为tcp+ip的字节大小。所以,如果收到的不是TCP/ACK,则需要在包的大小上加上IP的大小。如果目地址不是广播地址的话,那么设置其生存周期为( NETWORK_DIAMETER=30)。
else if(ih->saddr() == index) {
   drop(p, DROP_RTR_ROUTE_LOOP);
   return;
 }
发生环路,丢弃数据包。

 else {
 /*
  *  Check the TTL.  If it is zero, then discard.
  */
   if(--ih->ttl_ == 0) {
     drop(p, DROP_RTR_TTL);
     return;
   }
 }
检测数据包的生命周期,到期就丢弃。

接下来的判断

 if ( (u_int32_t)ih->daddr() != IP_BROADCAST)
   rt_resolve(p);
 else
   forward((aodv_rt_entry*) 0, p, NO_DELAY);
如果收到的这个数据包的目的地址不是广播地址,那么去检索路由表,否则如果是广播地址,那么立即发送出去。这里有一点需要注意,这个数据包可能是接收的来自其他节点,也有可能是自己产生的数据包。

因为我们先来分析发送数据包的情况,所以当对接收到PT_AODV类型的数据包时的调用一会儿再看。我们先来分析这种情况,如果这个数据包是来自我自身节点的TCP/UDP产生的,经上层的协议传过来并且要发送出去,作为路由协议,该如何处理(单播)?很明显,如果这个数据包是第一次要发送的数据包,那么这段代码肯定是第一次执行。

函数rt_resolve(p)被调用。

void
AODV::rt_resolve(Packet *p) {
struct hdr_cmn *ch = HDR_CMN(p);
struct hdr_ip *ih = HDR_IP(p);
aodv_rt_entry *rt;

 /*
  *  Set the transmit failure callback.  That
  *  won't change.
  */
 ch->xmit_failure_ = aodv_rt_failed_callback;
 ch->xmit_failure_data_ = (void*) this;
 rt = rtable.rt_lookup(ih->daddr());
 if(rt == 0) {
	  rt = rtable.rt_add(ih->daddr());
 }

 /*
  * If the route is up, forward the packet 
  */
	
 if(rt->rt_flags == RTF_UP) {
   assert(rt->rt_hops != INFINITY2);
   forward(rt, p, NO_DELAY);
 }
 /*
  *  if I am the source of the packet, then do a Route Request.
  */
  else if(ih->saddr() == index) {
   rqueue.enque(p);
   sendRequest(rt->rt_dst);
 }
 /*
  *	A local repair is in progress. Buffer the packet. 
  */
 else if (rt->rt_flags == RTF_IN_REPAIR) {
   rqueue.enque(p);
 }

 /*
  * I am trying to forward a packet for someone else to which
  * I don't have a route.
  */
 else {
 Packet *rerr = Packet::alloc();
 struct hdr_aodv_error *re = HDR_AODV_ERROR(rerr);
 /* 
  * For now, drop the packet and send error upstream.
  * Now the route errors are broadcast to upstream
  * neighbors - Mahesh 09/11/99
  */	
 
   assert (rt->rt_flags == RTF_DOWN);
   re->DestCount = 0;
   re->unreachable_dst[re->DestCount] = rt->rt_dst;
   re->unreachable_dst_seqno[re->DestCount] = rt->rt_seqno;
   re->DestCount += 1;
#ifdef DEBUG
   fprintf(stderr, "%s: sending RERR...\n", __FUNCTION__);
#endif
   sendError(rerr, false);

   drop(p, DROP_RTR_NO_ROUTE);
 }

}
首先,获取common和ip数据包头指针。申明  aodv_rt_entry *rt; 路由表指针。然后,在接下来的两条语句:

ch->xmit_failure_ = aodv_rt_failed_callback;
ch->xmit_failure_data_ = (void*) this;
在common包头中,给出了解释:

  // called if pkt can't obtain media or isn't ack'd. not called if
        // droped by a queue
        FailureCallback xmit_failure_;
        void *xmit_failure_data_;
其中FailureCallback是一个函数指针。因此,被申明为一个回调函数。当链路层传输失败的时候去调用  aodv_rt_failed_callback函数(主要用在修复阶段)。具体查看参考博客路由层传输失败回调函数2篇文章。

 rt = rtable.rt_lookup(ih->daddr());
 if(rt == 0) {
	  rt = rtable.rt_add(ih->daddr());
 }
先去查找本节点的路由表中有没有目的地址,如果没有,那么去增加。如果是第一次,那么肯定为0.
此时rt一定是为0的,所以调用rt_add函数。
aodv_rt_entry*
aodv_rtable::rt_add(nsaddr_t id)
{
aodv_rt_entry *rt;

 assert(rt_lookup(id) == 0);
 rt = new aodv_rt_entry;
 assert(rt);
 rt->rt_dst = id;
 LIST_INSERT_HEAD(&rthead, rt, rt_link);
 return rt;
}
调用函数:(列表查找指定的ID)
aodv_rt_entry*
aodv_rtable::rt_lookup(nsaddr_t id)
{
aodv_rt_entry *rt = rthead.lh_first;

 for(; rt; rt = rt->rt_link.le_next) {
   if(rt->rt_dst == id)
     break;
 }
 return rt;

}
此时如果没有对应的Id,即look_up==0,如果经过assert后断定为真,说明在路由表中没有这个目的地址。那么新建路由项,设定目的地址,并且插入表的头部。下面是在aodv_rt_entry的构造函数中,为一个路由项做的初始化工作;
odv_rt_entry::aodv_rt_entry()
{
int i;

 rt_req_timeout = 0.0;
 rt_req_cnt = 0;

 rt_dst = 0;
 rt_seqno = 0;
 rt_hops = rt_last_hop_count = INFINITY2;
 rt_nexthop = 0;
 LIST_INIT(&rt_pclist);
 rt_expire = 0.0;
 <span style="color:#ff0000;">rt_flags = RTF_DOWN;</span>

 /*
 rt_errors = 0;
 rt_error_time = 0.0;
 */


 for (i=0; i < MAX_HISTORY; i++) {
   rt_disc_latency[i] = 0.0;
 }
 hist_indx = 0;
 rt_req_last_ttl = 0;

 LIST_INIT(&rt_nblist);

}
由于初始化  rt_flags = RTF_DOWN 向下的,所以我们调用

 if(rt->rt_flags == RTF_UP) {
   assert(rt->rt_hops != INFINITY2);
   forward(rt, p, NO_DELAY);
 }
 /*
  *  if I am the source of the packet, then do a Route Request.
  */
   else if(ih->saddr() == index) {
   rqueue.enque(p);
   sendRequest(rt->rt_dst);
 }
将数据包加入队列,并且开始路由请求过程。这也正如AODV中一样,如果要发送一个数据包的时候,如果此时在路由表中没有要到达的目的地址的路由项,那么将此数据包入队,并且开始路由请求阶段。下面我么将到NS2实现的aodv_rqueue.h/aodv_rqueue.cc这2个文件,是如何实现对数据包存储功能的。






  • 1
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
NS2是一款常用的网络仿真工具,可以用来模拟网络各种协议的性能。AODV和DSR是两种常见的无线自组网络由协议,它们在不同的场景下有不同的优缺点。下面是我对这两种协议的仿真分析: 1. AODV协议 AODV(Ad-hoc On-Demand Distance Vector)协议是一种基于距离向量的由协议,它采用了按需由的方式,即只有在需要时才去寻找由,并且只维护已经建立的由。AODV协议每个节点都会维护一个由表,用于存储到达目的节点的下一跳节点和距离等信息。 在NS2,我们可以通过调整一些参数来模拟AODV协议的性能,如数据包传输延迟、由发现时间、由维护开销等。通过对这些参数进行不同的设置,我们可以得到不同的AODV协议性能指标。例如,我们可以通过比较不同节点数量下的数据包传输率、平均延迟等指标来评估AODV协议的性能。 2. DSR协议 DSR(Dynamic Source Routing)协议是一种基于源由的由协议,它不需要维护任何由表,而是将整个径存储在数据包。当一个节点需要发送数据时,它会向周围节点广播一个由请求包,然后等待其他节点的响应。一旦它收到足够的响应,就可以组装出完整的径,并将数据包发送到目的节点。 在NS2,我们可以通过调整一些参数来模拟DSR协议的性能,如由请求重传次数、由维护开销等。同样地,通过对这些参数进行不同的设置,我们可以得到不同的DSR协议性能指标。例如,我们可以通过比较不同节点数量下的由请求成功率、数据包传输延迟等指标来评估DSR协议的性能。 综上所述,通过NS2的仿真分析,我们可以对AODV和DSR协议的性能进行比较和评估,从而为无线自组网络的设计和优化提供参考。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值