📄 dsdv.cc
字号:
/* dsdv.cc $Id: dsdv.cc,v 1.1.1.1 2000/08/28 18:40:12 jinyang Exp $ */extern "C" {#include <stdarg.h>#include <float.h>};#include "dsdv.h"#include "priqueue.h"#include <random.h>#include <cmu/cmu-trace.h>#define DSDV_STARTUP_JITTER 2.0 // secs to jitter start of periodic activity from // when start-dsr msg sent to agent#define DSDV_ALMOST_NOW 0.1 // jitter used for events that should be effectively // instantaneous but are jittered to prevent // synchronization#define DSDV_BROADCAST_JITTER 0.01 // jitter for all broadcast packets#define DSDV_MIN_TUP_PERIOD 1.0 // minimum time between triggered updates#define IP_DEF_TTL 32 // default TTTL#define TRIGGER_UPDATE_ON_FRESH_SEQNUM/* should the receipt of a fresh (newer) sequence number cause us to send a triggered update? If undef'd, we'll only trigger on routing metric changes */// Returns a random number between 0 and maxstatic inline double jitter (double max, int be_random_){ return (be_random_ ? Random::uniform(max) : 0);}void DSDV_Agent::trace (char *fmt,...){ va_list ap; if (!tracetarget) return; va_start (ap, fmt); vsprintf (tracetarget->buffer (), fmt, ap); tracetarget->dump (); va_end (ap);}void DSDV_Agent::tracepkt (Packet * p, double now, int me, const char *type){ char buf[1024]; unsigned char *walk = p->accessdata (); int ct = *(walk++); int seq, dst, met; snprintf (buf, 1024, "V%s %.5f _%d_ [%d]:", type, now, me, ct); while (ct--) { dst = *(walk++); met = *(walk++); seq = *(walk++); seq = seq << 8 | *(walk++); seq = seq << 8 | *(walk++); seq = seq << 8 | *(walk++); snprintf (buf, 1024, "%s (%d,%d,%d)", buf, dst, met, seq); } // Now do trigger handling. //trace("VTU %.5f %d", now, me); if (verbose_) trace ("%s", buf);}// Prints out an rtable element.voidDSDV_Agent::output_rte(const char *prefix, rtable_ent * prte, DSDV_Agent * a){ a->trace("DFU: deimplemented"); printf("DFU: deimplemented"); prte = 0; prefix = 0;#if 0 printf ("%s%d %d %d %d %f %f %f %f 0x%08x\n", prefix, prte->dst, prte->hop, prte->metric, prte->seqnum, prte->udtime, prte->new_seqnum_at, prte->wst, prte->changed_at, (unsigned int) prte->timeout_event); a->trace ("VTE %.5f %d %d %d %d %f %f %f %f 0x%08x", Scheduler::instance ().clock (), prte->dst, prte->hop, prte->metric, prte->seqnum, prte->udtime, prte->new_seqnum_at, prte->wst, prte->changed_at, prte->timeout_event);#endif}class DSDVTriggerHandler : public Handler { public: DSDVTriggerHandler(DSDV_Agent *a_) { a = a_; } virtual void handle(Event *e); private: DSDV_Agent *a;};voidDSDVTriggerHandler::handle(Event *e) // send a triggered update (or a full update if one's needed){ Scheduler & s = Scheduler::instance (); Time now = s.clock (); rtable_ent *prte; int update_type; // we want periodic (=1) or triggered (=0) update? Time next_possible = a->lasttup_ + DSDV_MIN_TUP_PERIOD; for (a->table_->InitLoop(); (prte = a->table_->NextLoop()); ) if (prte->trigger_event == e) break; assert(prte && prte->trigger_event == e); if (now < next_possible) { s.schedule(a->trigger_handler, e, next_possible - now); a->cancelTriggersBefore(next_possible); return; } update_type = 0; Packet * p = a->makeUpdate(/*in-out*/update_type); if (p != NULL) { if (update_type == 1) { // we got a periodic update, though we only asked for triggered // cancel and reschedule periodic update s.cancel(a->periodic_callback_); s.schedule (a->helper_, a->periodic_callback_, a->perup_ * (0.75 + jitter (0.25, a->be_random_))); if (a->verbose_) a->tracepkt (p, now, a->myaddr_, "PU"); } else { if (a->verbose_) a->tracepkt (p, now, a->myaddr_, "TU"); } assert (!HDR_CMN (p)->xmit_failure_); // DEBUG 0x2 s.schedule (a->target_, p, jitter(DSDV_BROADCAST_JITTER, a->be_random_)); a->lasttup_ = now; // even if we got a full update, it still counts // for our last triggered update time } // free this event for (a->table_->InitLoop (); (prte = a->table_->NextLoop ());) if (prte->trigger_event && prte->trigger_event == e) { prte->trigger_event = 0; delete e; }}voidDSDV_Agent::cancelTriggersBefore(Time t) // Cancel any triggered events scheduled to take place *before* time // t (exclusive){ struct rtable_ent *prte; Scheduler & s = Scheduler::instance (); for (table_->InitLoop (); (prte = table_->NextLoop ());) if (prte->trigger_event && prte->trigger_event->time_ < t) { s.cancel(prte->trigger_event); delete prte->trigger_event; prte->trigger_event = 0; }}voidDSDV_Agent::needTriggeredUpdate(rtable_ent *prte, Time t) // if no triggered update already pending, make one so{ Scheduler & s = Scheduler::instance(); Time now = Scheduler::instance().clock(); assert(t >= now); if (prte->trigger_event) s.cancel(prte->trigger_event); else prte->trigger_event = new Event; s.schedule(trigger_handler, prte->trigger_event, t - now);}voidDSDV_Agent::helper_callback (Event * e){ Scheduler & s = Scheduler::instance (); double now = s.clock (); rtable_ent *prte; rtable_ent *pr2; int update_type; // we want periodic (=1) or triggered (=0) update? //printf("Triggered handler on 0x%08x\n", e); // Check for periodic callback if (periodic_callback_ && e == periodic_callback_) { update_type = 1; Packet *p = makeUpdate(/*in-out*/update_type); if (verbose_) { trace ("VPC %.5f _%d_", now, myaddr_); tracepkt (p, now, myaddr_, "PU"); } assert (!HDR_CMN (p)->xmit_failure_); // DEBUG 0x2 // send out update packet jitter to avoid sync s.schedule (target_, p, jitter(DSDV_BROADCAST_JITTER, be_random_)); // put the periodic update sending callback back onto the // the scheduler queue for next time.... s.schedule (helper_, periodic_callback_, perup_ * (0.75 + jitter (0.25, be_random_))); // this will take the place of any planned triggered updates lasttup_ = now; return; } // Check for timeout // If it was a timeout, fix the routing table. for (table_->InitLoop (); (prte = table_->NextLoop ());) if (prte->timeout_event && (prte->timeout_event == e)) break; // If it was a timeout, prte will be non-NULL // Note that in the if we don't touch the changed_at time, so that when // wst is computed, it doesn't consider the infinte metric the best // one at that sequence number. if (prte) { if (verbose_) { trace ("VTO %.5f _%d_ %d->%d", now, myaddr_, myaddr_, prte->dst); /* trace ("VTO %.5f _%d_ trg_sch %x on sched %x time %f", now, myaddr_, trigupd_scheduled, trigupd_scheduled ? s.lookup(trigupd_scheduled->uid_) : 0, trigupd_scheduled ? trigupd_scheduled->time_ : 0); */ } for (table_->InitLoop (); (pr2 = table_->NextLoop ()); ) { if (pr2->hop == prte->dst && pr2->metric != BIG) { if (verbose_) trace ("VTO %.5f _%d_ marking %d", now, myaddr_, pr2->dst); pr2->metric = BIG; pr2->advertise_ok_at = now; pr2->advert_metric = true; pr2->advert_seqnum = true; pr2->seqnum++; // And we have routing info to propogate. needTriggeredUpdate(pr2, now); } } // OK the timeout expired, so we'll free it. No dangling pointers. prte->timeout_event = 0; } else { // unknown event on queue fprintf(stderr,"DFU: unknown queue event\n"); abort(); } if (e) delete e;}voidDSDV_Agent::lost_link (Packet *p){ hdr_cmn *hdrc = HDR_CMN (p); rtable_ent *prte = table_->GetEntry (hdrc->next_hop_); if(use_mac_ == 0) { drop(p, DROP_RTR_MAC_CALLBACK); return; } if (verbose_ && hdrc->addr_type_ == AF_INET) trace ("VLL %.8f %d->%d lost at %d", Scheduler::instance ().clock (), ((hdr_ip *) p->access (off_ip_))->src_, ((hdr_ip *) p->access (off_ip_))->dst_, myaddr_); if (!use_mac_ || !prte || hdrc->addr_type_ != AF_INET) return; if (verbose_) trace ("VLP %.5f %d:%d->%d:%d lost at %d [hop %d]", Scheduler::instance ().clock (), ((hdr_ip *) p->access (off_ip_))->src_, ((hdr_ip *) p->access (off_ip_))->sport_, ((hdr_ip *) p->access (off_ip_))->dst_, ((hdr_ip *) p->access (off_ip_))->dport_, myaddr_, prte->dst); if (prte->timeout_event) { Scheduler::instance ().cancel (prte->timeout_event); helper_callback (prte->timeout_event); } else if (prte->metric != BIG) { assert(prte->timeout_event == 0); prte->timeout_event = new Event (); helper_callback (prte->timeout_event); } // Queue these packets up... recv(p, 0);#if 0 while (p2 = ((PriQueue *) target_)->filter (prte->dst)) { if (verbose_) trace ("VRS %.5f %d:%d->%d:%d lost at %d", Scheduler::instance ().clock (), ((hdr_ip *) p2->access (off_ip_))->src_, ((hdr_ip *) p2->access (off_ip_))->sport_, ((hdr_ip *) p2->access (off_ip_))->dst_, ((hdr_ip *) p2->access (off_ip_))->dport_, myaddr_); recv(p2, 0); } while (p2 = ll_queue->filter (prte->dst)) { if (verbose_) trace ("VRS %.5f %d:%d->%d:%d lost at %d", Scheduler::instance ().clock (), ((hdr_ip *) p2->access (off_ip_))->src_, ((hdr_ip *) p2->access (off_ip_))->sport_, ((hdr_ip *) p2->access (off_ip_))->dst_, ((hdr_ip *) p2->access (off_ip_))->dport_, myaddr_); recv (p2, 0); }#endif}static void mac_callback (Packet * p, void *arg){ ((DSDV_Agent *) arg)->lost_link (p);}Packet *DSDV_Agent::makeUpdate(int& periodic) // return a packet advertising the state in the routing table // makes a full ``periodic'' update if requested, or a ``triggered'' // partial update if there are only a few changes and full update otherwise // returns with periodic = 1 if full update returned, or = 0 if partial // update returned{ Packet *p = allocpkt (); hdr_ip *iph = (hdr_ip *) p->access (off_ip_); hdr_cmn *hdrc = HDR_CMN (p); double now = Scheduler::instance ().clock (); rtable_ent *prte; unsigned char *walk; int change_count; // count of entries to go in this update int rtbl_sz; // counts total entries in rt table int unadvertiseable; // number of routes we can't advertise yet //printf("Update packet from %d [per=%d]\n", myaddr_, periodic); // The packet we send wants to be broadcast hdrc->next_hop_ = IP_BROADCAST; hdrc->addr_type_ = AF_INET; iph->dst_ = IP_BROADCAST; iph->dport_ = ROUTER_PORT; change_count = 0; rtbl_sz = 0; unadvertiseable = 0; for (table_->InitLoop (); (prte = table_->NextLoop ()); ) { rtbl_sz++; if ((prte->advert_seqnum || prte->advert_metric) && prte->advertise_ok_at <= now) change_count++; if (prte->advertise_ok_at > now) unadvertiseable++; } if (change_count * 3 > rtbl_sz && change_count > 3) { // much of the table has changed, just do a periodic update now periodic = 1; } // Periodic update... increment the sequence number... if (periodic) { change_count = rtbl_sz - unadvertiseable; assert(change_count >= 1); /* should always be an advertiseable route for ourselves in the table */#if 0 trace("DAM %.5f _%d_ sz %d cc %d unat %d", now, myaddr_, rtbl_sz, change_count, unadvertiseable);#endif rtable_ent rte; bzero(&rte, sizeof(rte)); /* inc sequence number on any periodic update, even if we started off wanting to do a triggered update, b/c we're doing a real live periodic update now that'll take the place of our next periodic update */ seqno_ += 2; rte.dst = myaddr_; rte.hop = iph->src_; rte.metric = 0; rte.seqnum = seqno_; rte.advertise_ok_at = 0.0; // can always advert ourselves rte.advert_seqnum = true; // always include ourselves in Triggered Upds rte.changed_at = now; rte.new_seqnum_at = now; rte.wst = 0; rte.timeout_event = 0; // Don't time out our localhost :) rte.q = 0; // Don't buffer pkts for self! /* this add isn't going to increase the size of the table, since a route for ourselves was inserted at startup, but serves to refresh all the variables in the table to values set above */ table_->AddEntry (rte); } if (change_count == 0) { Packet::free(p); // allocated by us, no drop needed return NULL; // nothing to advertise } /* ****** make the update packet.... *********** with less than 100+ nodes, an update for all nodes is less than the MTU, so don't bother worrying about splitting the update over multiple packets -dam 4/26/98 */ assert(rtbl_sz <= (1500 / 12)); p->allocdata ((change_count * 6) + 1); walk = p->accessdata (); *(walk++) = change_count; hdrc->size_ = change_count * 12 + IP_HDR_LEN; // DSDV + IP#if 0 int jjj = 0;#endif for (table_->InitLoop (); (prte = table_->NextLoop ());) {#if 0 jjj++; trace("DAM %.5f _%d_ jjj %d cc %d -dst %d ok at %f", now, myaddr_, jjj, change_count, prte->dst, prte->advertise_ok_at );#endif if (periodic && prte->advertise_ok_at > now) { // don't send out routes that shouldn't be advertised // even in periodic updates continue; } if (periodic || ((prte->advert_seqnum || prte->advert_metric) && prte->advertise_ok_at <= now)) { // include this rte in the advert if (!periodic && verbose_) trace ("VCT %.5f _%d_ %d", now, myaddr_, prte->dst); assert (prte->dst < 256 && prte->metric < 256); *(walk++) = prte->dst; *(walk++) = prte->metric; *(walk++) = (prte->seqnum) >> 24; *(walk++) = ((prte->seqnum) >> 16) & 0xFF; *(walk++) = ((prte->seqnum) >> 8) & 0xFF; *(walk++) = (prte->seqnum) & 0xFF; prte->last_advertised_metric = prte->metric; // seqnum's only need to be advertised once after they change prte->advert_seqnum = false; // don't need to advert seqnum again if (periodic) { // a full advert means we don't have to re-advert either // metrics or seqnums again until they change prte->advert_seqnum = false; prte->advert_metric = false; } change_count--; } } assert(change_count == 0); return p;}voidDSDV_Agent::updateRoute(struct rtable_ent *old_rte, struct rtable_ent *new_rte){ assert(new_rte); Time now = Scheduler::instance().clock();
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -