//#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; /*AODVclass 只有两个函数,构造函数和creat函数*/ 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; /*command函数实现了命令的分发*/ int AODV::command(int argc, const char*const* argv) { if(argc == 2) {//命令的参数个数是2 Tcl& tcl = Tcl::instance(); if(strncasecmp(argv[1], "id", 2) == 0) {//命令所要求的操作为id tcl.resultf("%d", index); return TCL_OK; } if(strncasecmp(argv[1], "start", 2) == 0) {//命令所要求的操作为start 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) {//命令参数个数等于3 if(strcmp(argv[1], "index") == 0) {//命令所要求的操作为index index = atoi(argv[2]); return TCL_OK; } //命令所要求的操作为log-target或者tracetarget 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) { //命令所要求的操作为drop-target int stat = rqueue.command(argc,argv); if (stat != TCL_OK) return stat; return Agent::command(argc, argv); } //命令所要求的操作if-queue else if(strcmp(argv[1], "if-queue") == 0) { ifqueue = (PriQueue*) TclObject::lookup(argv[2]); if(ifqueue == 0) return TCL_ERROR; return TCL_OK; } //命令所要求的操作为port-dmux 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); } //hello报文定时器 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. */ /*邻居链路down掉,处理*/ 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);//将此路由down掉 } // 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; } /*将此路由条目down掉*/ 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. */ 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); } } /*定时查看路由缓存条目*/ 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; //如果此路由条目标注为有效,但是生存时间为0 //丢弃前往目的分组,并且将此路由条目down掉 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; } } //如果此路由条目已经down掉,但是有前往目的的分组,则发送路由请求 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. //如果分组类型是AODV类型,则交给recvAodv函数 if(ch->ptype() == PT_AODV) { ih->ttl_ -= 1; recvAODV(p); return; } /* * Must be a packet I'm originating... */ //如果是我发送的报文,加上包头,ch->num_forward()是转发的跳数 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 //如果不是广播报文,交给re_resolve函数处理;如果是广播报文,则转发 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); struct hdr_ip *ih = HDR_IP(p); assert(ih->sport() == RT_PORT); assert(ih->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) { 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) { #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)) { #ifdef DEBUG fprintf(stderr, "%s: discarding request\n", __FUNCTION__); #endif // DEBUG Packet::free(p); return; } /* * Cache the broadcast ID */ /*缓存此路由请求*/ id_insert(rq->rq_src, rq->rq_bcast_id); /* * We are either going to forward the REQUEST or generate a * REPLY. Before we do anything, we make sure that the REVERSE * route is in the route table. */ //建立反向路径 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)); /*如果请求序列号大于路由序列号或者两者序列号相等但是跳数 比源路由跳数小,则更新*/ if ( (rq->rq_src_seqno > rt0->rt_seqno ) || ((rq->rq_src_seqno == rt0->rt_seqno) && (rq->rq_hop_count < rt0->rt_hops)) ) { // 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 */ /*如果有到反向路径的分组报文,则发送*/ 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. */ //寻找到目的节点的路由 rt = rtable.rt_lookup(rq->rq_dst); // 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 // 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. /*如果不是目的节点,但是有到目的节点的路径,也发送路由应答报文*/ 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, rq->rq_dst, 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); // 加入前缀列表 rt0->pc_insert(rt->rt_nexthop); // 加入前缀列表 #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 // 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. 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) { //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. */ // Note that rp_dst is the dest of the data packets, not the // the dest of the reply, which is the src of the data packets. rt = rtable.rt_lookup(rp->rp_dst);//建立反向路径 /* * 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 // Update the rt entry rt_update(rt, rp->rp_dst_seqno, rp->rp_hop_count, rp->rp_src, CURRENT_TIME + rp->rp_lifetime); // 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 // Update the route discovery latency statistics // rp->rp_timestamp is the time of request origination rt->rt_disc_latency[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 // may drop packets. -SRD 5/23/99 forward(rt, buf_pkt, delay); delay += ARP_DELAY; } } } else { suppress_reply = 1;//序列号过小且没有更小的跳数 } /* * If reply is for me, discard it. */ if(ih->daddr() == index || suppress_reply) {//如果此节点是源节点或者应答报文不够新且没有更小的跳数 Packet::free(p); } /* * Otherwise, forward the Route Reply. */ 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) { 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); // 奇数代表无穷大,无效的意思 #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);//将此路由down掉 // Not sure whether this is the right thing to do /*查看队列中是否有下一跳是此邻居的分组 若有的话,直接丢包;具体请看queue/priqueue.cc的filter函数*/ 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; } /*如果不是AODV数据包并且链路方向是上行并且是广播包或者此节点就是目的地址*/ if (ch->ptype() != PT_AODV && ch->direction() == hdr_cmn::UP && ((u_int32_t)ih->daddr() == IP_BROADCAST) || ((u_int32_t)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 { // 非广播报文 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) { // 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) { 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. //如果请求次数大于最大的发送请求次数,则丢掉分组,不发送请求 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; } #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. // Dynamic TTL evaluation - SRD 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; else { // 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. // The factor 2.0 is just to be safe .. SRD 5/22/99 // 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 // 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.); } void AODV::sendReply(nsaddr_t ipdst, u_int32_t hop_count, nsaddr_t rpdst, u_int32_t rpseq, u_int32_t lifetime, double timestamp) { 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); #ifdef DEBUG fprintf(stderr, "sending Reply from %d at %.2f\n", index, Scheduler::instance().clock()); #endif // DEBUG assert(rt); rp->rp_type = AODVTYPE_RREP; //rp->rp_flags = 0x00; rp->rp_hop_count = hop_count; rp->rp_dst = rpdst; rp->rp_dst_seqno = rpseq; rp->rp_src = index; 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; 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) { 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() { 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); } } }