📄 dsdvroutetable.cc
字号:
/* * dsdvroutetable.{cc,hh} -- DSDV routing element * Douglas S. J. De Couto * * Copyright (c) 2002 Massachusetts Institute of Technology * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, subject to the conditions * listed in the Click LICENSE file. These conditions include: you must * preserve this copyright notice, and you cannot mention the copyright * holders in advertising related to the Software without their permission. * The Software is provided WITHOUT ANY WARRANTY, EXPRESS OR IMPLIED. This * notice is a summary of the Click LICENSE file; the license in that file is * legally binding. */#include <click/config.h>#include <stddef.h>#include <click/confparse.hh>#include <click/error.hh>#include <clicknet/ether.h>#include <clicknet/ip.h>#include <click/standard/scheduleinfo.hh>#include <click/router.hh>#include <click/element.hh>#include <click/glue.hh>#include <click/straccum.hh>#include <click/packet_anno.hh>#include <elements/grid/dsdvroutetable.hh>#include <elements/grid/linkstat.hh>#include <elements/grid/gridgatewayinfo.hh>#include <elements/grid/timeutils.hh>// #include <elements/wifi/txfeedbackstats.hh>CLICK_DECLS#define DBG 0#define DBG2 0#define DBG3 0#define FULL_DUMP_ON_TRIG_UPDATE 0#define max(a, b) ((a) > (b) ? (a) : (b))#define min(a, b) ((a) < (b) ? (a) : (b))#define dsdv_assert(e) ((e) ? (void) 0 : dsdv_assert_(__FILE__, __LINE__, #e))boolDSDVRouteTable::get_one_entry(const IPAddress &dest_ip, RouteEntry &entry){ RTEntry r; bool res = lookup_route(dest_ip, r); if (res) entry = r; return res;}boolDSDVRouteTable::lookup_route(const IPAddress &dest_ip, RTEntry &entry){#if ENABLE_PAUSE if (_paused) { RTEntry *r =_snapshot_rtes.findp(dest_ip); if (r == 0) return false;#if USE_OLD_SEQ if (use_old_route(dest_ip, _snapshot_jiffies)) r = _snapshot_old_rtes.findp(dest_ip);#endif entry = *r; return true; }#endif RTEntry *r = _rtes.findp(dest_ip); if (r == 0) return false;#if USE_OLD_SEQ if (use_old_route(dest_ip, dsdv_jiffies())) r = _old_rtes.findp(dest_ip);#endif entry = *r; return true;}voidDSDVRouteTable::get_all_entries(Vector<RouteEntry> &vec){#if ENABLE_PAUSE if (_paused) { for (RTIter iter = _snapshot_rtes.begin(); iter.live(); iter++) { const RTEntry &rte = iter.value();#if USE_OLD_SEQ if (use_old_route(rte.dest_ip, _snapshot_jiffies)) vec.push_back(_snapshot_old_rtes[rte.dest_ip]); else vec.push_back(rte);#else vec.push_back(rte);#endif return; } }#endif#if USE_OLD_SEQ unsigned jiff = dsdv_jiffies();#endif for (RTIter iter = _rtes.begin(); iter.live(); iter++) { const RTEntry &rte = iter.value();#if USE_OLD_SEQ if (use_old_route(rte.dest_ip, jiff)) vec.push_back(_old_rtes[rte.dest_ip]); else vec.push_back(rte);#else vec.push_back(rte);#endif }}unsignedDSDVRouteTable::get_number_direct_neigbors(){ Vector<RouteEntry> v; // delegate to avoid repeating all the pause/old seq logic get_all_entries(v); // assume all direct neighbors are one-hop neighbors, and count // those instead int num_nbrs = 0; for (int i = 0; i < v.size(); i++) if (v[i].num_hops() == 1 && v[i].good()) num_nbrs++; return num_nbrs;}#if USE_OLD_SEQboolDSDVRouteTable::use_old_route(const IPAddress &dst, unsigned jiff){ if (!_use_old_route) return false; RTEntry *real = _rtes.findp(dst); RTEntry *old = _old_rtes.findp(dst);#if ENABLE_PAUSE if (_paused) { real = _snapshot_rtes.findp(dst); old = _snapshot_old_rtes.findp(dst); }#endif#if USE_GOOD_NEW_ROUTES // never use an old route if the new one is better if (_use_good_new_route && real && old && metric_preferable(*real, *old)) return false;#endif return (real && real->good() && // if real route is bad, don't use good but old route old && old->good() && // if old route is bad, don't use it real->advertise_ok_jiffies > jiff); // if ok to advertise real route, don't use old route}#endifDSDVRouteTable::DSDVRouteTable() :#if SEQ_METRIC _use_seq_metric(false),#endif _gw_info(0), _metric(0), _log(0), _seq_no(0), _mtu(2000), _bcast_count(0), _max_hops(3), _alpha(88), _wst0(6000), _last_periodic_update(0), _last_triggered_update(0), _ignore_invalid_routes(false), _hello_timer(static_hello_hook, this), _log_dump_timer(static_log_dump_hook, this), _verbose(true){}DSDVRouteTable::~DSDVRouteTable(){ for (TMIter i = _expire_timers.begin(); i.live(); i++) { if (i.value()->scheduled()) i.value()->unschedule(); delete i.value(); } for (TMIter i = _trigger_timers.begin(); i.live(); i++) { if (i.value()->scheduled()) i.value()->unschedule(); delete i.value(); } for (HMIter i = _expire_hooks.begin(); i.live(); i++) delete i.value(); for (HMIter i = _trigger_hooks.begin(); i.live(); i++) delete i.value();}void *DSDVRouteTable::cast(const char *n){ if (strcmp(n, "DSDVRouteTable") == 0) return (DSDVRouteTable *) this; else if (strcmp(n, "GridGenericRouteTable") == 0) return (GridGenericRouteTable *) this; else return 0;}intDSDVRouteTable::configure(Vector<String> &conf, ErrorHandler *errh){ String logfile; int res = cp_va_kparse(conf, this, errh, "TIMEOUT", cpkP+cpkM, cpUnsigned, &_timeout, "PERIOD", cpkP+cpkM, cpUnsigned, &_period, "JITTER", cpkP+cpkM, cpUnsigned, &_jitter, "MIN_TRIGGER_PERIOD", cpkP+cpkM, cpUnsigned, &_min_triggered_update_period, "ETH", cpkP+cpkM, cpEthernetAddress, &_eth, "IP", cpkP+cpkM, cpIPAddress, &_ip, "VERBOSE", 0, cpBool, &_verbose, "GW", 0, cpElement, &_gw_info, "MAX_HOPS", 0, cpUnsigned, &_max_hops, "METRIC", 0, cpElement, &_metric, "LOG", 0, cpElement, &_log, "WST0", 0, cpUnsigned, &_wst0, "ALPHA", 0, cpUnsigned, &_alpha, "SEQ0", 0, cpUnsigned, &_seq_no, "MTU", 0, cpUnsigned, &_mtu, "IGNORE_INVALID_ROUTES", 0, cpBool, &_ignore_invalid_routes,#if SEQ_METRIC "USE_SEQ_METRIC", 0, cpBool, &_use_seq_metric,#endif cpEnd); if (res < 0) return res; if (_seq_no & 1) return errh->error("initial sequence number must be even"); if (_timeout == 0) return errh->error("timeout interval must be greater than 0"); if (_period == 0) return errh->error("period must be greater than 0"); // _jitter is allowed to be 0 if (_jitter > _period) return errh->error("jitter is bigger than period"); if (_max_hops == 0) return errh->error("max hops must be greater than 0"); if (_alpha > 100) return errh->error("alpha must be between 0 and 100 inclusive"); if (_mtu < sizeof(click_ether) + sizeof(grid_hdr) + sizeof(grid_hello)) return errh->error("mtu is too small to send a route ads"); if (_log && _log->cast("GridGenericLogger") == 0) return errh->error("LOG element is not a GridGenericLogger"); if (_gw_info && _gw_info->cast("GridGatewayInfo") == 0) return errh->error("GW element is not a GridGatewayInfo"); if (_metric && _metric->cast("GridGenericMetric") == 0) return errh->error("METRIC element is not a GridGenericMetric"); if (_gw_info == 0 && _verbose) errh->warning("No GridGatewayInfo element specified, will default to not advertising as gateway"); if (_metric == 0 && _verbose) errh->warning("No metric elements specified, will default to minimum hop-count");#if SEQ_METRIC if (_metric && _use_seq_metric) errh->warning("USE_SEQ_METRIC has been specified, the specified METRIC element will be ignored");#endif return res;}intDSDVRouteTable::initialize(ErrorHandler *){ _hello_timer.initialize(this); _hello_timer.schedule_after_msec(_period); _log_dump_timer.initialize(this); _log_dump_timer.schedule_after_msec(_log_dump_period); check_invariants();#if ENABLE_PAUSE _paused = false;#endif#if USE_OLD_SEQ _use_old_route = false;#if USE_GOOD_NEW_ROUTES _use_good_new_route = false;#endif#endif#if ENABLE_SEEN _use_seen = false;#endif return 0;}boolDSDVRouteTable::current_gateway(RouteEntry &gw){ RTEntry best; bool found_gateway = false; Vector<IPAddress> gw_addrs; RTIter i = _rtes.begin();#if ENABLE_PAUSE if (_paused) i = _snapshot_rtes.begin();#endif for ( ; i.live(); i++) { if (i.value().is_gateway) gw_addrs.push_back(i.value().dest_ip); } for (Vector<IPAddress>::const_iterator i = gw_addrs.begin(); i != gw_addrs.end(); i++) { RTEntry r; bool res = lookup_route(*i, r); dsdv_assert(res); if (r.is_gateway && r.good() && (!found_gateway || metric_preferable(r, best))) { best = r; found_gateway = true; } } if (found_gateway) { gw = best; } return found_gateway;}voidDSDVRouteTable::insert_route(const RTEntry &r, const GridGenericLogger::reason_t why){ check_invariants(); r.check(); dsdv_assert(!_ignore_invalid_routes || r.metric.good()); RTEntry *old_r = _rtes.findp(r.dest_ip); // invariant check: running timers exist for all current good // routes. no timers or bogus timer entries exist for bad routes. // hook objects exist for each timer. Timer **old = _expire_timers.findp(r.dest_ip); HookPair **oldhp = _expire_hooks.findp(r.dest_ip); if (old_r && old_r->good()) dsdv_assert(old && *old && (*old)->scheduled() && oldhp && *oldhp); else { dsdv_assert(old == 0); dsdv_assert(oldhp == 0); } // get rid of old expire timer if (old) { (*old)->unschedule(); delete *old; delete *oldhp; _expire_timers.remove(r.dest_ip); _expire_hooks.remove(r.dest_ip); } // Note: ns dsdv only schedules a timeout for the sender of each // route ad, relying on the next-hop expiry logic to get all routes // via that next hop. However, that won't work for general metrics, // so we install a timeout for *every* newly installed good route. if (r.good()) { HookPair *hp = new HookPair(this, r.dest_ip); Timer *t = new Timer(static_expire_hook, (void *) hp); t->initialize(this); t->schedule_after_msec(min(r.ttl, _timeout)); _expire_timers.insert(r.dest_ip, t); _expire_hooks.insert(r.dest_ip, hp); }#if USE_OLD_SEQ // if we are getting new seqno, save route for old seqno if (old_r && old_r->seq_no() < r.seq_no()) _old_rtes.insert(r.dest_ip, *old_r);#endif _rtes.insert(r.dest_ip, r); // note, we don't change any pending triggered update for this // updated dest. ... but shouldn't we postpone it? -- shouldn't // matter if timer fires too early, since the advertise_ok_jiffies // should tell us it's too early. if (_log) _log->log_added_route(why, make_generic_rte(r), (unsigned int) r.wst); check_invariants();}voidDSDVRouteTable::expire_hook(const IPAddress &ip){ check_invariants(&ip); // invariant check: // 1. route to expire should exist RTEntry *r = _rtes.findp(ip); dsdv_assert(r != 0); // 2. route to expire should be good dsdv_assert(r->good() && (r->seq_no() & 1) == 0); // 3. the expire timer for this dest should exist, but should not be // running. Timer **old = _expire_timers.findp(ip); HookPair **oldhp = _expire_hooks.findp(ip); dsdv_assert(old && *old && !(*old)->scheduled() && oldhp && *oldhp); if (_log) { _log->log_start_expire_handler(Timestamp::now());
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -