NS2中无线网络模拟之三(AODV路由分析2)
来源:互联网 发布:查工商银行余额软件 编辑:程序博客网 时间:2024/05/16 03:54
在分析AODV路由协议时,首先要明白,AODV只是一个路由协议,它的本质工作就是去管理路由表,所有的更新工作只是在实现对路由表的增、删、改、查工作。下面,我们继续之前的分析。
首先,我选择的切入点当然是从路由请求开始,分析源码,看它如何实现,关键代码贴出来分析:
我们从recv函数来分析
主函数
voidAODV::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.
调用函数
voidAODV::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)被调用。
voidAODV::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个文件,是如何实现对数据包存储功能的。
0 0
- NS2中无线网络模拟之三(AODV路由分析)
- NS2中无线网络模拟之三(AODV路由分析2)
- NS2中无线网络模拟之三(AODV路由分析3)
- NS2中无线网络模拟之三(AODV路由分析4)
- NS2中无线网络模拟之三(AODV路由分析5)
- NS2中无线网络模拟之二
- NS2中无线网络模拟之一
- ns2--AODV协议分析
- aodv路由协议分析
- aodv路由协议分析
- aodv路由协议分析
- 亲测可用的NS2对"1. AODV" "2. DSDV" "3. DSR" 的路由模拟
- NS2仿真分析无线网络的攻击防御(2)
- 基于NS2的网络路由协议仿真(AODV、COPE+AODV)
- 利用NS2进行无线网络模拟
- NS2下AODV协议aodv.cc源码分析
- NS2中AODV协议混杂模式配置
- NS2中DSDV, AODV, DSR协议评估
- 大小不固定的图片、多行文字的水平垂直居中
- 线程与多线程
- 总序:第一次CSDN博客记录
- 51Nod-1490-多重游戏
- 链表回文
- NS2中无线网络模拟之三(AODV路由分析2)
- php 中preg的使用
- 子字符串查找或匹配(暴力法,KMP)
- Centos6.6上源码安装Nodejs V4版本
- 几种经典排序算法
- Leetcode 91 Decode Ways
- Angular页面传参办法
- hdu2444——The Accomodation of Students(判断二分图+匈牙利算法)
- 那些年玩过的“旁注”