/* Copyright (c) 1997, 1998 Carnegie Mellon University. All Rights Reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. The name of the author may not be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. The AODV code developed by the CMU/MONARCH group was optimized and tuned by Samir Das and Mahesh Marina, University of Cincinnati. The work was partially done in Sun Microsystems. Modified for gratuitous replies by Anant Utgikar, 09/16/02. */ //#include <ip.h> #include <aodv/aodv.h> #include <aodv/aodv_packet.h> #include <random.h> #include <cmu-trace.h> //#include <energy-model.h> #define max(a,b) ( (a) > (b) ? (a) : (b) ) #define CURRENT_TIME Scheduler::instance().clock() //#define DEBUG //#define ERROR #ifdef DEBUG static int extra_route_reply = 0; static int limit_route_request = 0; static int route_request = 0; #endif /* TCL Hooks */ int hdr_aodv::offset_; static class AODVHeaderClass : public PacketHeaderClass { public: AODVHeaderClass() : PacketHeaderClass("PacketHeader/AODV", sizeof(hdr_all_aodv)) { bind_offset(&hdr_aodv::offset_); } } class_rtProtoAODV_hdr; static class AODVclass : public TclClass { public: AODVclass() : TclClass("Agent/AODV") {} TclObject* create(int argc, const char*const* argv) { assert(argc == 5); //return (new AODV((nsaddr_t) atoi(argv[4]))); return (new AODV((nsaddr_t) Address::instance().str2addr(argv[4]))); } } class_rtProtoAODV; int AODV::command(int argc, const char*const* argv) { if(argc == 2) { Tcl& tcl = Tcl::instance(); if(strncasecmp(argv[1], "id", 2) == 0) { tcl.resultf("%d", index); return TCL_OK; } if(strncasecmp(argv[1], "start", 2) == 0) { btimer.handle((Event*) 0); #ifndef AODV_LINK_LAYER_DETECTION htimer.handle((Event*) 0); ntimer.handle((Event*) 0); #endif // LINK LAYER DETECTION rtimer.handle((Event*) 0); return TCL_OK; } } else if(argc == 3) { if(strcmp(argv[1], "index") == 0) { index = atoi(argv[2]); return TCL_OK; } else if(strcmp(argv[1], "log-target") == 0 || strcmp(argv[1], "tracetarget") == 0) { logtarget = (Trace*) TclObject::lookup(argv[2]); if(logtarget == 0) return TCL_ERROR; return TCL_OK; } else if(strcmp(argv[1], "drop-target") == 0) { int stat = rqueue.command(argc,argv); if (stat != TCL_OK) return stat; return Agent::command(argc, argv); } else if(strcmp(argv[1], "if-queue") == 0) { ifqueue = (PriQueue*) TclObject::lookup(argv[2]); if(ifqueue == 0) return TCL_ERROR; return TCL_OK; } else if (strcmp(argv[1], "port-dmux") == 0) { dmux_ = (PortClassifier *)TclObject::lookup(argv[2]); if (dmux_ == 0) { fprintf (stderr, "%s: %s lookup of %s failed/n", __FILE__, argv[1], argv[2]); return TCL_ERROR; } return TCL_OK; } } return Agent::command(argc, argv); } /* Constructor */ AODV::AODV(nsaddr_t id) : Agent(PT_AODV), btimer(this), htimer(this), ntimer(this), rtimer(this), lrtimer(this), rqueue() { index = id; seqno = 2; bid = 1; LIST_INIT(&nbhead); LIST_INIT(&bihead); logtarget = 0; ifqueue = 0; } /* Timers */ void BroadcastTimer::handle(Event*) { agent->id_purge(); Scheduler::instance().schedule(this, &intr, BCAST_ID_SAVE); } void HelloTimer::handle(Event*) { agent->sendHello(); double interval = MinHelloInterval + ((MaxHelloInterval - MinHelloInterval) * Random::uniform()); assert(interval >= 0); Scheduler::instance().schedule(this, &intr, interval); } void NeighborTimer::handle(Event*) { agent->nb_purge(); Scheduler::instance().schedule(this, &intr, HELLO_INTERVAL); } void RouteCacheTimer::handle(Event*) { agent->rt_purge(); #define FREQUENCY 0.5 // sec Scheduler::instance().schedule(this, &intr, FREQUENCY); } void LocalRepairTimer::handle(Event* p) { // SRD: 5/4/99 aodv_rt_entry *rt; struct hdr_ip *ih = HDR_IP( (Packet *)p); /* you get here after the timeout in a local repair attempt */ /* fprintf(stderr, "%s/n", __FUNCTION__); */ rt = agent->rtable.rt_lookup(ih->daddr()); if (rt && rt->rt_flags != RTF_UP) { // route is yet to be repaired // I will be conservative and bring down the route // and send route errors upstream. /* The following assert fails, not sure why */ /* assert (rt->rt_flags == RTF_IN_REPAIR); */ //rt->rt_seqno++; agent->rt_down(rt); // send RERR #ifdef DEBUG fprintf(stderr,"Node %d: Dst - %d, failed local repair/n",index, rt->rt_dst); #endif } Packet::free((Packet *)p); } /* Broadcast ID Management Functions */ void AODV::id_insert(nsaddr_t id, u_int32_t bid) { BroadcastID *b = new BroadcastID(id, bid); assert(b); b->expire = CURRENT_TIME + BCAST_ID_SAVE; LIST_INSERT_HEAD(&bihead, b, link); } /* SRD */ bool AODV::id_lookup(nsaddr_t id, u_int32_t bid) { BroadcastID *b = bihead.lh_first; // Search the list for a match of source and bid for( ; b; b = b->link.le_next) { if ((b->src == id) && (b->id == bid)) return true; } return false; } void AODV::id_purge() { BroadcastID *b = bihead.lh_first; BroadcastID *bn; double now = CURRENT_TIME; for(; b; b = bn) { bn = b->link.le_next; if(b->expire <= now) { LIST_REMOVE(b,link); delete b; } } } /* Helper Functions */ double AODV::PerHopTime(aodv_rt_entry *rt) { int num_non_zero = 0, i; double total_latency = 0.0; if (!rt) return ((double) NODE_TRAVERSAL_TIME ); for (i=0; i < MAX_HISTORY; i++) { if (rt->rt_disc_latency[i] > 0.0) { num_non_zero++; total_latency += rt->rt_disc_latency[i]; } } if (num_non_zero > 0) return(total_latency / (double) num_non_zero); else return((double) NODE_TRAVERSAL_TIME); } /* Link Failure Management Functions */ static void aodv_rt_failed_callback(Packet *p, void *arg) { ((AODV*) arg)->rt_ll_failed(p); } /* * This routine is invoked when the link-layer reports a route failed. */ void AODV::rt_ll_failed(Packet *p) { struct hdr_cmn *ch = HDR_CMN(p); struct hdr_ip *ih = HDR_IP(p); aodv_rt_entry *rt; nsaddr_t broken_nbr = ch->next_hop_; #ifndef AODV_LINK_LAYER_DETECTION drop(p, DROP_RTR_MAC_CALLBACK); #else /* * Non-data packets and Broadcast Packets can be dropped. */ if(! DATA_PACKET(ch->ptype()) || (u_int32_t) ih->daddr() == IP_BROADCAST) { drop(p, DROP_RTR_MAC_CALLBACK); return; } log_link_broke(p); if((rt = rtable.rt_lookup(ih->daddr())) == 0) { drop(p, DROP_RTR_MAC_CALLBACK); return; } log_link_del(ch->next_hop_); #ifdef AODV_LOCAL_REPAIR /* if the broken link is closer to the dest than source, attempt a local repair. Otherwise, bring down the route. */ if (ch->num_forwards() > rt->rt_hops) { local_rt_repair(rt, p); // local repair // retrieve all the packets in the ifq using this link, // queue the packets for which local repair is done, return; } else #endif // LOCAL REPAIR { drop(p, DROP_RTR_MAC_CALLBACK); // Do the same thing for other packets in the interface queue using the // broken link -Mahesh while((p = ifqueue->filter(broken_nbr))) { drop(p, DROP_RTR_MAC_CALLBACK); } nb_delete(broken_nbr); } #endif // LINK LAYER DETECTION } void AODV::handle_link_failure(nsaddr_t id) { aodv_rt_entry *rt, *rtn; Packet *rerr = Packet::alloc(); struct hdr_aodv_error *re = HDR_AODV_ERROR(rerr); re->DestCount = 0; for(rt = rtable.head(); rt; rt = rtn) { // for each rt entry rtn = rt->rt_link.le_next; if ((rt->rt_hops != INFINITY2) && (rt->rt_nexthop == id) ) { assert (rt->rt_flags == RTF_UP); assert((rt->rt_seqno%2) == 0); rt->rt_seqno++; re->unreachable_dst[re->DestCount] = rt->rt_dst; re->unreachable_dst_seqno[re->DestCount] = rt->rt_seqno; #ifdef DEBUG fprintf(stderr, "%s(%f): %d/t(%d/t%u/t%d)/n", __FUNCTION__, CURRENT_TIME, index, re->unreachable_dst[re->DestCount], re->unreachable_dst_seqno[re->DestCount], rt->rt_nexthop); #endif // DEBUG re->DestCount += 1; rt_down(rt); } // remove the lost neighbor from all the precursor lists rt->pc_delete(id); } if (re->DestCount > 0) { #ifdef DEBUG fprintf(stderr, "%s(%f): %d/tsending RERR.../n", __FUNCTION__, CURRENT_TIME, index); #endif // DEBUG sendError(rerr, false); } else { Packet::free(rerr); } } void AODV::local_rt_repair(aodv_rt_entry *rt, Packet *p) { #ifdef DEBUG fprintf(stderr,"%s: Dst - %d/n", __FUNCTION__, rt->rt_dst); #endif // Buffer the packet rqueue.enque(p); // mark the route as under repair rt->rt_flags = RTF_IN_REPAIR; sendRequest(rt->rt_dst); // set up a timer interrupt Scheduler::instance().schedule(&lrtimer, p->copy(), rt->rt_req_timeout); } void AODV::rt_update(aodv_rt_entry *rt, u_int32_t seqnum, u_int16_t metric, nsaddr_t nexthop, double expire_time) { rt->rt_seqno = seqnum; rt->rt_hops = metric; rt->rt_flags = RTF_UP; rt->rt_nexthop = nexthop; rt->rt_expire = expire_time; } void AODV::rt_down(aodv_rt_entry *rt) { /* * Make sure that you don't "down" a route more than once. */ if(rt->rt_flags == RTF_DOWN) { return; } // assert (rt->rt_seqno%2); // is the seqno odd? rt->rt_last_hop_count = rt->rt_hops; rt->rt_hops = INFINITY2; rt->rt_flags = RTF_DOWN; rt->rt_nexthop = 0; rt->rt_expire = 0; } /* rt_down function */ /* Route Handling Functions */ 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. */ //如果本节点是该分组的源节点,那么说明没有到目的节点的路由,发送RREQ找路。 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. */ //本节点转发数据分组,但是不知道到目的节点的路由,发送RRER说明链路中断。 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); } } void AODV::rt_purge() { aodv_rt_entry *rt, *rtn; double now = CURRENT_TIME; double delay = 0.0; Packet *p; for(rt = rtable.head(); rt; rt = rtn) { // for each rt entry rtn = rt->rt_link.le_next; if ((rt->rt_flags == RTF_UP) && (rt->rt_expire < now)) { // if a valid route has expired, purge all packets from // send buffer and invalidate the route. assert(rt->rt_hops != INFINITY2); while((p = rqueue.deque(rt->rt_dst))) { #ifdef DEBUG fprintf(stderr, "%s: calling drop()/n", __FUNCTION__); #endif // DEBUG drop(p, DROP_RTR_NO_ROUTE); } rt->rt_seqno++; assert (rt->rt_seqno%2); rt_down(rt); } else if (rt->rt_flags == RTF_UP) { // If the route is not expired, // and there are packets in the sendbuffer waiting, // forward them. This should not be needed, but this extra // check does no harm. assert(rt->rt_hops != INFINITY2); while((p = rqueue.deque(rt->rt_dst))) { forward (rt, p, delay); delay += ARP_DELAY; } } else if (rqueue.find(rt->rt_dst)) // If the route is down and // if there is a packet for this destination waiting in // the sendbuffer, then send out route request. sendRequest // will check whether it is time to really send out request // or not. // This may not be crucial to do it here, as each generated // packet will do a sendRequest anyway. sendRequest(rt->rt_dst); } } /* Packet Reception Routines */ 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) {//判断是不是aodv的包,如果是的话那么就调用recvAODV(p) ih->ttl_ -= 1; recvAODV(p); return; } /* * Must be a packet I'm originating... */ //本节点产生的aodv包,添加ip头; if((ih->saddr() == index) && (ch->num_forwards() == 0)) { /* * Add the IP Header */ 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. */ //TTL是分组最多可以转发的次数。 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); } 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); } } void AODV::recvRequest(Packet *p) {//收到RREQ struct hdr_ip *ih = HDR_IP(p); struct hdr_aodv_request *rq = HDR_AODV_REQUEST(p); aodv_rt_entry *rt; /* * Drop if: * - I'm the source * - I recently heard this request. */ if(rq->rq_src == index) { //看看这个request是不是自己发出来的。 #ifdef DEBUG fprintf(stderr, "%s: got my own REQUEST/n", __FUNCTION__); #endif // DEBUG Packet::free(p); //如果是的话就将这个包丢弃。 return; } if (id_lookup(rq->rq_src, rq->rq_bcast_id)) {//看看是不是曾经收到过的rreq. //两个判据一个是request source(源节点IP地址) 一个是 广播序列号 #ifdef DEBUG fprintf(stderr, "%s: discarding request/n", __FUNCTION__); #endif // DEBUG Packet::free(p); //如果是的话就丢弃 return; } /* * Cache the broadcast ID */ //用于判断是否已经收到过该RREQ id_insert(rq->rq_src, rq->rq_bcast_id); //刷新自己节点的RREQ的broadcast id(就是RREQ) /* 在这种情况下我们有两种选择,一种是将RREQ继续传播下去,一种是产生RREP * 在这之前我们要确定,反向路由已经在路由表中存在。如果存在反向路由,在考虑 是否应该想源节点发送RREP */ aodv_rt_entry *rt0; // rt0 is the reverse route rt0 = rtable.rt_lookup(rq->rq_src); //寻找反向路由 if(rt0 == 0) { /* if not in the route table 如果不在路由表中的话*/ // create an entry for the reverse route. rt0 = rtable.rt_add(rq->rq_src); //将反向路由写入路由表 } rt0->rt_expire = max(rt0->rt_expire, (CURRENT_TIME + REV_ROUTE_LIFE)); //定义ROUTE的生命期 if ( (rq->rq_src_seqno > rt0->rt_seqno ) || ((rq->rq_src_seqno == rt0->rt_seqno) && (rq->rq_hop_count < rt0->rt_hops)) ) { //这里就是路由判据,当遇到新的RREQ的时候 //比较在路由表中已经存在的到目的节点的路由,比较目的节点的序列号(用来保证使用最新路由 //防止路由环)在目的节点序列号相同的情况下,采用跳数较小的。在这种情况下 //就更新路由表。 // If we have a fresher seq no. or lesser #hops for the // same seq no., update the rt entry. Else don't bother. rt_update(rt0, rq->rq_src_seqno, rq->rq_hop_count, ih->saddr(), max(rt0->rt_expire, (CURRENT_TIME + REV_ROUTE_LIFE)) ); //上面两行命令就是如何更新路由表,更新路由表中的哪些项。 if (rt0->rt_req_timeout > 0.0) { // Reset the soft state and // Set expiry time to CURRENT_TIME + ACTIVE_ROUTE_TIMEOUT // This is because route is used in the forward direction, // but only sources get benefited by this change rt0->rt_req_cnt = 0; rt0->rt_req_timeout = 0.0; rt0->rt_req_last_ttl = rq->rq_hop_count; rt0->rt_expire = CURRENT_TIME + ACTIVE_ROUTE_TIMEOUT; } /* Find out whether any buffered packet can benefit from the * reverse route. * May need some change in the following code - Mahesh 09/11/99 */ //缓存中是否有到源节点的路由,有则删除,无则添加 //缓存中是否有到源节点的数据分组,有则,建立好路由开始发送数据。 //查找是否有到目的节点的有效路由,有则向源节点发送RREP,没有则继续发送RREQ。 //注意转发前要更新RREQ的部分内容; assert (rt0->rt_flags == RTF_UP); Packet *buffered_pkt; while ((buffered_pkt = rqueue.deque(rt0->rt_dst))) { if (rt0 && (rt0->rt_flags == RTF_UP)) { assert(rt0->rt_hops != INFINITY2); forward(rt0, buffered_pkt, NO_DELAY); } } } // End for putting reverse route in rt table /*反向路径已经清楚了(搞定了) * We have taken care of the reverse route stuff. * Now see whether we can send a route reply. //现在就看看是否应该在此节点处发送RREP */ rt = rtable.rt_lookup(rq->rq_dst);//在路由表中查找目的节点是RREQ_DEST的路由参看aodv_rtable //.cc文件中的rt_lookup函数。 // First check if I am the destination .. if(rq->rq_dst == index) { #ifdef DEBUG fprintf(stderr, "%d - %s: destination sending reply/n", index, __FUNCTION__); #endif // DEBUG // Just to be safe, I use the max. Somebody may have为了安全起见,使用目的节点序列号最大 //的路由+1 // incremented the dst seqno. seqno = max(seqno, rq->rq_dst_seqno)+1; if (seqno%2) seqno++;//如果目的节点序列号是奇数就将其变成偶数,保证目的节点序列号是偶数 sendReply(rq->rq_src, // IP Destination目的节点IP 1, // Hop Count index, // Dest IP Address seqno, // Dest Sequence Num目的节点序列号 MY_ROUTE_TIMEOUT, // Lifetime rq->rq_timestamp); // timestamp没搞清楚什么东西 Packet::free(p); //释放RREQ ,产生RREP(这是后话) #ifdef DEBUG fprintf(stderr, "%d - %s: destination sending reply/n", index, __FUNCTION__); #endif // DEBUG // Just to be safe, I use the max. Somebody may have // incremented the dst seqno. seqno = max(seqno, rq->rq_dst_seqno)+1; if (seqno%2) seqno++; sendReply(rq->rq_src, // IP Destination 1, // Hop Count index, // Dest IP Address seqno, // Dest Sequence Num MY_ROUTE_TIMEOUT, // Lifetime rq->rq_timestamp); // timestamp Packet::free(p); } // I am not the destination, but I may have a fresh enough route. //如果不是destination,但是有够新的路由 else if (rt && (rt->rt_hops != INFINITY2) && (rt->rt_seqno >= rq->rq_dst_seqno) ) {//保证够新(目的节点序列号) //assert (rt->rt_flags == RTF_UP); assert(rq->rq_dst == rt->rt_dst); //assert ((rt->rt_seqno%2) == 0); // is the seqno even? sendReply(rq->rq_src, rt->rt_hops + 1, //如果是目的节点的话就设成一,这里不是目的节点就在 //这个RREQ中的跳数加1; rq->rq_dst, //如果是目的节点这一项就是目的节点的IP地址(这个节点本身的地址), //这里是RREQ中的目的节点IP地址 rt->rt_seqno, (u_int32_t) (rt->rt_expire - CURRENT_TIME), // rt->rt_expire - CURRENT_TIME, rq->rq_timestamp); // Insert nexthops to RREQ source and RREQ destination in the // precursor lists of destination and source respectively //将下一跳节点分别加入前向路由,反向路由中; rt->pc_insert(rt0->rt_nexthop); // nexthop to RREQ source rt0->pc_insert(rt->rt_nexthop); // nexthop to RREQ destination #ifdef RREQ_GRAT_RREP sendReply(rq->rq_dst, rq->rq_hop_count, rq->rq_src, rq->rq_src_seqno, (u_int32_t) (rt->rt_expire - CURRENT_TIME), // rt->rt_expire - CURRENT_TIME,就是剩下的生命周期 rq->rq_timestamp); #endif // TODO: send grat RREP to dst if G flag set in RREQ using rq->rq_src_seqno, rq->rq_hop_counT //产生RREP发向源节点(RREP的目的节点)RREP中使用RREQ中的rq->rq_src_seqno,rq->rq_hop_count // DONE: Included gratuitous replies to be sent as per IETF aodv draft specification. //As of now, G flag has not been dynamically used and is always set or reset in aodv-packet.h --- Anant Utgikar, 09/16/02. //G flag用来设定或者重设aodv packet. Packet::free(p); } /* * Can't reply. So forward the Route Request */ // else { ih->saddr() = index; ih->daddr() = IP_BROADCAST; rq->rq_hop_count += 1; // Maximum sequence number seen en route if (rt) rq->rq_dst_seqno = max(rt->rt_seqno, rq->rq_dst_seqno); forward((aodv_rt_entry*) 0, p, DELAY); } } void AODV::recvReply(Packet *p) { //查看是否有到目的节点的路由,没有则建立,否则就更新。 //如果收到信息的节点是RREP的目的节点也就是发送信息的源节点,则建立到目的节点的路由。 //否则根据路由表中到源节点的路由(这个路由在建立RREQ的过程中已经建立,也就是 //reverse路由)转发RREP; //struct hdr_cmn *ch = HDR_CMN(p); struct hdr_ip *ih = HDR_IP(p); struct hdr_aodv_reply *rp = HDR_AODV_REPLY(p); aodv_rt_entry *rt; char suppress_reply = 0; double delay = 0.0; #ifdef DEBUG fprintf(stderr, "%d - %s: received a REPLY/n", index, __FUNCTION__); #endif // DEBUG /* * Got a reply. So reset the "soft state" maintained for * route requests in the request table. We don't really have * have a separate request table. It is just a part of the * routing table itself. 收到一个reply就更新发送请求表,但是没有单独的发送请求表, //发送请求表示路由表的一部分。 */ // Note that rp_dst(RREP_dest) is the dest of the data packets, not the // the dest of the reply(不是REPLY的终点), which is the src of the data packets. //而是数据包的的源点。 rt = rtable.rt_lookup(rp->rp_dst); /* 收到reply后就查看这个reply是否已经收到过。 * If I don't have a rt entry to this host... adding */ if(rt == 0) { //如果没有收到就就将其添加进路由表中。 rt = rtable.rt_add(rp->rp_dst); } /* * Add a forward route table entry... here I am following * Perkins-Royer AODV paper almost literally - SRD 5/99 */ if ( (rt->rt_seqno < rp->rp_dst_seqno) || // newer route ((rt->rt_seqno == rp->rp_dst_seqno) && (rt->rt_hops > rp->rp_hop_count)) ) { // shorter or better route //还是路由判据,如果收到reply就比较以前收到的reply目的节点序列号,如果目的节点序列号相同就比较 //比较跳数,取跳数较小的,然后将不合格的RREP删除。 //aodv的RREQ没走一步就会建立一个反向路径就会产生一个RREP,然后将跳数以及中间节点, //目的节点序列号 //加入路由表中, // Update the rt entry rt_update(rt, rp->rp_dst_seqno, rp->rp_hop_count, rp->rp_src, CURRENT_TIME + rp->rp_lifetime); //参看这个文件中的rt_update函数。 // reset the soft state rt->rt_req_cnt = 0; rt->rt_req_timeout = 0.0; rt->rt_req_last_ttl = rp->rp_hop_count; if (ih->daddr() == index) { // If I am the original source,如果收到rrep的是源节点 // Update the route discovery latency statistics,更新路由发现潜存策略 // rp->rp_timestamp is the time of request origination??????不清楚 rt->rt_disc_latency[(unsigned char)rt->hist_indx] = (CURRENT_TIME - rp->rp_timestamp) / (double) rp->rp_hop_count; // increment indx for next time rt->hist_indx = (rt->hist_indx + 1) % MAX_HISTORY; } /* * Send all packets queued in the sendbuffer destined for * this destination. 路由建立之后将放在缓存区中的要发向目的节点所有数据包都发出去。 * XXX - observe the "second" use of p. */ Packet *buf_pkt; while((buf_pkt = rqueue.deque(rt->rt_dst))) { if(rt->rt_hops != INFINITY2) { assert (rt->rt_flags == RTF_UP); // Delay them a little to help ARP. Otherwise ARP //我们都知道ns软件中有ARP模块(连接链路层)用来将ip地址转化为mac地址.这个过程需要时间,所以 //要为它设定预留延迟,否则就会出现丢包现象 // may drop packets. -SRD 5/23/99 forward(rt, buf_pkt, delay); delay += ARP_DELAY;//为ARP模块预留命令 } } } else { //如果收到RREP的不是源节点 suppress_reply = 1; } /* * If reply is for me, discard it. *如果目的节点受到了rrep直接DISCARD */ if(ih->daddr() == index || suppress_reply) { Packet::free(p); } /* * Otherwise, forward the Route Reply. *不是的话就继续向前发rrep */ else { // Find the rt entry aodv_rt_entry *rt0 = rtable.rt_lookup(ih->daddr()); // If the rt is up, forward if(rt0 && (rt0->rt_hops != INFINITY2)) { assert (rt0->rt_flags == RTF_UP); rp->rp_hop_count += 1; rp->rp_src = index; forward(rt0, p, NO_DELAY); // // Insert the nexthop towards the RREQ source to // the precursor list of the RREQ destination rt->pc_insert(rt0->rt_nexthop); // nexthop to RREQ source } else { // I don't know how to forward .. drop the reply. #ifdef DEBUG fprintf(stderr, "%s: dropping Route Reply/n", __FUNCTION__); #endif // DEBUG drop(p, DROP_RTR_NO_ROUTE); } } } void AODV::recvError(Packet *p) {//收到RERR,查看那些路径受到了中断链路的影响, //更新RERR,并向受影响的节点发送RERR struct hdr_ip *ih = HDR_IP(p); struct hdr_aodv_error *re = HDR_AODV_ERROR(p); aodv_rt_entry *rt; u_int8_t i; Packet *rerr = Packet::alloc(); struct hdr_aodv_error *nre = HDR_AODV_ERROR(rerr); nre->DestCount = 0; for (i=0; i<re->DestCount; i++) { // For each unreachable destination rt = rtable.rt_lookup(re->unreachable_dst[i]); if ( rt && (rt->rt_hops != INFINITY2) && (rt->rt_nexthop == ih->saddr()) && (rt->rt_seqno <= re->unreachable_dst_seqno[i]) ) { assert(rt->rt_flags == RTF_UP); assert((rt->rt_seqno%2) == 0); // is the seqno even? #ifdef DEBUG fprintf(stderr, "%s(%f): %d/t(%d/t%u/t%d)/t(%d/t%u/t%d)/n", __FUNCTION__,CURRENT_TIME, index, rt->rt_dst, rt->rt_seqno, rt->rt_nexthop, re->unreachable_dst[i],re->unreachable_dst_seqno[i], ih->saddr()); #endif // DEBUG rt->rt_seqno = re->unreachable_dst_seqno[i]; rt_down(rt); // Not sure whether this is the right thing to do Packet *pkt; while((pkt = ifqueue->filter(ih->saddr()))) { drop(pkt, DROP_RTR_MAC_CALLBACK); } // if precursor list non-empty add to RERR and delete the precursor list if (!rt->pc_empty()) { nre->unreachable_dst[nre->DestCount] = rt->rt_dst; nre->unreachable_dst_seqno[nre->DestCount] = rt->rt_seqno; nre->DestCount += 1; rt->pc_delete(); } } } if (nre->DestCount > 0) { #ifdef DEBUG fprintf(stderr, "%s(%f): %d/t sending RERR.../n", __FUNCTION__, CURRENT_TIME, index); #endif // DEBUG sendError(rerr); } else { Packet::free(rerr); } Packet::free(p); } /* Packet Transmission Routines */ void AODV::forward(aodv_rt_entry *rt, Packet *p, double delay) { struct hdr_cmn *ch = HDR_CMN(p); struct hdr_ip *ih = HDR_IP(p); if(ih->ttl_ == 0) { #ifdef DEBUG fprintf(stderr, "%s: calling drop()/n", __PRETTY_FUNCTION__); #endif // DEBUG drop(p, DROP_RTR_TTL); return; } if (ch->ptype() != PT_AODV && ch->direction() == hdr_cmn::UP && ((u_int32_t)ih->daddr() == IP_BROADCAST) || (ih->daddr() == here_.addr_)) { dmux_->recv(p,0); return; } if (rt) { assert(rt->rt_flags == RTF_UP); rt->rt_expire = CURRENT_TIME + ACTIVE_ROUTE_TIMEOUT; ch->next_hop_ = rt->rt_nexthop; ch->addr_type() = NS_AF_INET; ch->direction() = hdr_cmn::DOWN; //important: change the packet's direction } else { // if it is a broadcast packet // assert(ch->ptype() == PT_AODV); // maybe a diff pkt type like gaf assert(ih->daddr() == (nsaddr_t) IP_BROADCAST); ch->addr_type() = NS_AF_NONE; ch->direction() = hdr_cmn::DOWN; //important: change the packet's direction } if (ih->daddr() == (nsaddr_t) IP_BROADCAST) { // If it is a broadcast packet assert(rt == 0); /* * Jitter the sending of broadcast packets by 10ms */ Scheduler::instance().schedule(target_, p, 0.01 * Random::uniform()); } else { // Not a broadcast packet if(delay > 0.0) { Scheduler::instance().schedule(target_, p, delay); } else { // Not a broadcast packet, no delay, send immediately Scheduler::instance().schedule(target_, p, 0.); } } } void AODV::sendRequest(nsaddr_t dst) {//发送RREQ // Allocate a RREQ packet Packet *p = Packet::alloc(); struct hdr_cmn *ch = HDR_CMN(p); struct hdr_ip *ih = HDR_IP(p); struct hdr_aodv_request *rq = HDR_AODV_REQUEST(p); aodv_rt_entry *rt = rtable.rt_lookup(dst);//添加到目的节点的路由,此时路由是不可用的,无效。 assert(rt); /* * Rate limit sending of Route Requests. We are very conservative * about sending out route requests. */ if (rt->rt_flags == RTF_UP) {//不清楚 assert(rt->rt_hops != INFINITY2); Packet::free((Packet *)p); return; } if (rt->rt_req_timeout > CURRENT_TIME) {//不到RREQ的发送时间,注意文件开头的RREQ定时器 //若没有收到RREP,那么要定时发送RREQ; Packet::free((Packet *)p); return; } // rt_req_cnt is the no. of times we did network-wide broadcast // RREQ_RETRIES is the maximum number we will allow before // going to a long timeout.生命期就是我们允许RREQ重播的次数 //如果AODV中多次发送RREQ,仍然找不到到目的节点的路由,那么丢包。(这个if中代码干的事) if (rt->rt_req_cnt > RREQ_RETRIES) { rt->rt_req_timeout = CURRENT_TIME + MAX_RREQ_TIMEOUT; rt->rt_req_cnt = 0; Packet *buf_pkt; while ((buf_pkt = rqueue.deque(rt->rt_dst))) { drop(buf_pkt, DROP_RTR_NO_ROUTE); } Packet::free((Packet *)p); return; } //下面的内容是填充路由表以及RREQ数据分组的内容,需要结合路由表文件来看。 #ifdef DEBUG fprintf(stderr, "(%2d) - %2d sending Route Request, dst: %d/n", ++route_request, index, rt->rt_dst); #endif // DEBUG // Determine the TTL to be used this time. 动态的确定这次RREQ的生命期, // Dynamic TTL evaluation - SRD 用SRD来球RREQ。 rt->rt_req_last_ttl = max(rt->rt_req_last_ttl,rt->rt_last_hop_count); if (0 == rt->rt_req_last_ttl) { // first time query broadcast第一次广播 ih->ttl_ = TTL_START; } else { // Expanding ring search. if (rt->rt_req_last_ttl < TTL_THRESHOLD) ih->ttl_ = rt->rt_req_last_ttl + TTL_INCREMENT;//逐步增加生命周期,知道最大值(TTL_ //_THRESHOLD) else {//如果已经超期了,那么RREQ的广播次数加一 // network-wide broadcast ih->ttl_ = NETWORK_DIAMETER; rt->rt_req_cnt += 1; } } // remember the TTL used for the next time rt->rt_req_last_ttl = ih->ttl_; // PerHopTime is the roundtrip time per hop for route requests.每一跳的时间,就是ROUTE //REQUEST在两节点间传播一次时间 // The factor 2.0 is just to be safe .. SRD 5/22/99将这个时间设成2.0是比较安全的, //当然我们也可以改 // Also note that we are making timeouts to be larger if we have // done network wide broadcast before. rt->rt_req_timeout = 2.0 * (double) ih->ttl_ * PerHopTime(rt); //? if (rt->rt_req_cnt > 0)//如果不是第一次传播 rt->rt_req_timeout *= rt->rt_req_cnt; rt->rt_req_timeout += CURRENT_TIME; // Don't let the timeout to be too large, however .. SRD 6/8/99如果不想让生命期太长 if (rt->rt_req_timeout > CURRENT_TIME + MAX_RREQ_TIMEOUT) rt->rt_req_timeout = CURRENT_TIME + MAX_RREQ_TIMEOUT; rt->rt_expire = 0; #ifdef DEBUG fprintf(stderr, "(%2d) - %2d sending Route Request, dst: %d, tout %f ms/n", ++route_request, index, rt->rt_dst, rt->rt_req_timeout - CURRENT_TIME); #endif // DEBUG // Fill out the RREQ packet 填写RREQ数据包的各个元素。 // ch->uid() = 0; ch->ptype() = PT_AODV; ch->size() = IP_HDR_LEN + rq->size(); ch->iface() = -2; ch->error() = 0; ch->addr_type() = NS_AF_NONE; ch->prev_hop_ = index; // AODV hack ih->saddr() = index; ih->daddr() = IP_BROADCAST; ih->sport() = RT_PORT; ih->dport() = RT_PORT; // Fill up some more fields. rq->rq_type = AODVTYPE_RREQ; rq->rq_hop_count = 1; rq->rq_bcast_id = bid++; rq->rq_dst = dst; rq->rq_dst_seqno = (rt ? rt->rt_seqno : 0); rq->rq_src = index; seqno += 2; assert ((seqno%2) == 0); rq->rq_src_seqno = seqno; rq->rq_timestamp = CURRENT_TIME; Scheduler::instance().schedule(target_, p, 0.); } //这个函数主要是填充RREP的内容(我注解的可能有问题) void AODV::sendReply(nsaddr_t ipdst, u_int32_t hop_count, nsaddr_t rpdst, u_int32_t rpseq, u_int32_t lifetime, double timestamp) { //目的节点IP地址,从源节点到目的节点的跳数,rrep目的节点(源节点IP地址), //目的节点序列号,生命周期,最后一个不清楚 Packet *p = Packet::alloc(); struct hdr_cmn *ch = HDR_CMN(p); struct hdr_ip *ih = HDR_IP(p); struct hdr_aodv_reply *rp = HDR_AODV_REPLY(p); aodv_rt_entry *rt = rtable.rt_lookup(ipdst); /*这个就是lookup函数 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; } */ #ifdef DEBUG fprintf(stderr, "sending Reply from %d at %.2f/n", index, Scheduler::instance().clock()); #endif // DEBUG assert(rt); rp->rp_type = AODVTYPE_RREP; //确定数据包的类型为RREP //rp->rp_flags = 0x00; rp->rp_hop_count = hop_count; // hop_count = rt_hops + 1,通告上一个节点到达目的节点的跳书 rp->rp_dst = rpdst; //路由询问rq的目标IP地址 rp->rp_dst_seqno = rpseq; rp->rp_src = index; //rq的源是本节点的IP地址 rp->rp_lifetime = lifetime; rp->rp_timestamp = timestamp; // ch->uid() = 0; ch->ptype() = PT_AODV; ch->size() = IP_HDR_LEN + rp->size(); ch->iface() = -2; ch->error() = 0; ch->addr_type() = NS_AF_INET; ch->next_hop_ = rt->rt_nexthop; ch->prev_hop_ = index; // AODV hack ch->direction() = hdr_cmn::DOWN; ih->saddr() = index; //定义了发送节点的ip地址 ih->daddr() = ipdst; //目的节点 ih->sport() = RT_PORT; ih->dport() = RT_PORT; ih->ttl_ = NETWORK_DIAMETER; Scheduler::instance().schedule(target_, p, 0.); } void AODV::sendError(Packet *p, bool jitter) {//链路中断,需要发送RRER。 //通知所有受影响的节点,函数体关于填充RRER的内容,不用细看。 struct hdr_cmn *ch = HDR_CMN(p); struct hdr_ip *ih = HDR_IP(p); struct hdr_aodv_error *re = HDR_AODV_ERROR(p); #ifdef ERROR fprintf(stderr, "sending Error from %d at %.2f/n", index, Scheduler::instance().clock()); #endif // DEBUG re->re_type = AODVTYPE_RERR; //re->reserved[0] = 0x00; re->reserved[1] = 0x00; // DestCount and list of unreachable destinations are already filled // ch->uid() = 0; ch->ptype() = PT_AODV; ch->size() = IP_HDR_LEN + re->size(); ch->iface() = -2; ch->error() = 0; ch->addr_type() = NS_AF_NONE; ch->next_hop_ = 0; ch->prev_hop_ = index; // AODV hack ch->direction() = hdr_cmn::DOWN; //important: change the packet's direction ih->saddr() = index; ih->daddr() = IP_BROADCAST; ih->sport() = RT_PORT; ih->dport() = RT_PORT; ih->ttl_ = 1; // Do we need any jitter? Yes if (jitter) Scheduler::instance().schedule(target_, p, 0.01*Random::uniform()); else Scheduler::instance().schedule(target_, p, 0.0); } /* Neighbor Management Functions */ void AODV::sendHello() {//周期发送HELLOW分组,以检测邻居节点的联通性。 Packet *p = Packet::alloc(); struct hdr_cmn *ch = HDR_CMN(p); struct hdr_ip *ih = HDR_IP(p); struct hdr_aodv_reply *rh = HDR_AODV_REPLY(p); #ifdef DEBUG fprintf(stderr, "sending Hello from %d at %.2f/n", index, Scheduler::instance().clock()); #endif // DEBUG rh->rp_type = AODVTYPE_HELLO; //rh->rp_flags = 0x00; rh->rp_hop_count = 1; rh->rp_dst = index; rh->rp_dst_seqno = seqno; rh->rp_lifetime = (1 + ALLOWED_HELLO_LOSS) * HELLO_INTERVAL; // ch->uid() = 0; ch->ptype() = PT_AODV; ch->size() = IP_HDR_LEN + rh->size(); ch->iface() = -2; ch->error() = 0; ch->addr_type() = NS_AF_NONE; ch->prev_hop_ = index; // AODV hack ih->saddr() = index; ih->daddr() = IP_BROADCAST; ih->sport() = RT_PORT; ih->dport() = RT_PORT; ih->ttl_ = 1; Scheduler::instance().schedule(target_, p, 0.0); } void AODV::recvHello(Packet *p) { //struct hdr_ip *ih = HDR_IP(p); struct hdr_aodv_reply *rp = HDR_AODV_REPLY(p); AODV_Neighbor *nb; nb = nb_lookup(rp->rp_dst); if(nb == 0) { nb_insert(rp->rp_dst); } else { nb->nb_expire = CURRENT_TIME + (1.5 * ALLOWED_HELLO_LOSS * HELLO_INTERVAL); } Packet::free(p); } void AODV::nb_insert(nsaddr_t id) { AODV_Neighbor *nb = new AODV_Neighbor(id); assert(nb); nb->nb_expire = CURRENT_TIME + (1.5 * ALLOWED_HELLO_LOSS * HELLO_INTERVAL); LIST_INSERT_HEAD(&nbhead, nb, nb_link); seqno += 2; // set of neighbors changed assert ((seqno%2) == 0); } AODV_Neighbor* AODV::nb_lookup(nsaddr_t id) { AODV_Neighbor *nb = nbhead.lh_first; for(; nb; nb = nb->nb_link.le_next) { if(nb->nb_addr == id) break; } return nb; } /* * Called when we receive *explicit* notification that a Neighbor * is no longer reachable. */ void AODV::nb_delete(nsaddr_t id) { AODV_Neighbor *nb = nbhead.lh_first; log_link_del(id); seqno += 2; // Set of neighbors changed assert ((seqno%2) == 0); for(; nb; nb = nb->nb_link.le_next) { if(nb->nb_addr == id) { LIST_REMOVE(nb,nb_link); delete nb; break; } } handle_link_failure(id); } /* * Purges all timed-out Neighbor Entries - runs every * HELLO_INTERVAL * 1.5 seconds. */ void AODV::nb_purge() { AODV_Neighbor *nb = nbhead.lh_first; AODV_Neighbor *nbn; double now = CURRENT_TIME; for(; nb; nb = nbn) { nbn = nb->nb_link.le_next; if(nb->nb_expire <= now) { nb_delete(nb->nb_addr); } } }