00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017 #ifdef HAVE_CONFIG_H
00018 #include <dtn-config.h>
00019 #endif
00020
00021 #include <algorithm>
00022 #include <oasys/debug/DebugUtils.h>
00023
00024 #include "DTLSRRouter.h"
00025 #include "bundling/BundleDaemon.h"
00026 #include "bundling/SDNV.h"
00027 #include "bundling/TempBundle.h"
00028 #include "contacts/ContactManager.h"
00029 #include "routing/RouteTable.h"
00030 #include "session/Session.h"
00031
00032 namespace oasys {
00033
00034
00035 template<>
00036 const char*
00037 InlineFormatter<dtn::DTLSRRouter::EdgeInfo>
00038 ::format(const dtn::DTLSRRouter::EdgeInfo& ei)
00039 {
00040 const char* state_str;
00041 if (ei.params_.state_ == dtn::DTLSRRouter::LinkParams::LINK_UP) {
00042 state_str = "UP";
00043 } else if (ei.params_.state_ == dtn::DTLSRRouter::LinkParams::LINK_DOWN) {
00044 state_str = "DOWN";
00045 } else {
00046 state_str = "__UNKNOWN__";
00047 }
00048
00049 buf_.appendf("%s: state=%s cost=%u delay=%u bw=%u",
00050 ei.id_.c_str(), state_str,
00051 ei.params_.cost_, ei.params_.delay_, ei.params_.bw_);
00052 return buf_.c_str();
00053 }
00054
00055 }
00056
00057 namespace dtn {
00058
00059
00060 class DTLSRRouter::CostWeightFn : public RoutingGraph::WeightFn {
00061 public:
00062 u_int32_t operator()(const RoutingGraph::SearchInfo& info,
00063 const RoutingGraph::Edge* edge)
00064 {
00065 (void)info;
00066 if (edge->info().params_.state_ == LinkParams::LINK_DOWN) {
00067 return 0xffffffff;
00068 }
00069 return edge->info().params_.cost_;
00070 }
00071 };
00072
00073
00074 class DTLSRRouter::DelayWeightFn : public RoutingGraph::WeightFn {
00075 public:
00076 u_int32_t operator()(const RoutingGraph::SearchInfo& info,
00077 const RoutingGraph::Edge* edge)
00078 {
00079 (void)info;
00080
00081 u_int32_t downtime = (info.now_ - edge->info().last_update_).sec_;
00082 if (DTLSRConfig::instance()->lsa_interval_ != 0 &&
00083 downtime > (2 * DTLSRConfig::instance()->lsa_interval_))
00084 {
00085
00086 return 0xffffffff;
00087 }
00088
00089 if (edge->info().params_.state_ == LinkParams::LINK_DOWN) {
00090 return 0xffffffff;
00091 }
00092 return edge->info().params_.delay_;
00093 }
00094 };
00095
00096
00097 class DTLSRRouter::EstimatedDelayWeightFn : public RoutingGraph::WeightFn {
00098 public:
00099 EstimatedDelayWeightFn(DTLSRRouter* rtr)
00100 : router_(rtr) {}
00101
00102 u_int32_t operator()(const RoutingGraph::SearchInfo& info,
00103 const RoutingGraph::Edge* edge)
00104 {
00105 if (edge->info().params_.state_ == LinkParams::LINK_DOWN) {
00106
00107
00108 u_int32_t downtime = (info.now_ - edge->info().last_update_).sec_;
00109
00110
00111
00112
00113
00114
00115
00116
00117
00118
00119
00120 u_int32_t ret = (downtime + 5) >> DTLSRConfig::instance()->weight_shift_;
00121
00122 if (ret < 24*60*60) {
00123 log_debug_p("/dtn/route/graph",
00124 "weight of edge %s=%u (downtime %u + 5)",
00125 edge->info().id_.c_str(), ret, downtime);
00126 } else {
00127 ret = 24*60*60;
00128 log_warn_p("/dtn/route/graph",
00129 "weight of edge %s=%u: (downtime %u exceeded max)",
00130 edge->info().id_.c_str(), ret, downtime);
00131 }
00132
00133 return ret;
00134 }
00135
00136 u_int32_t qlen, qsize;
00137
00138 qlen = edge->info().params_.qcount_;
00139 qsize = edge->info().params_.qsize_;
00140
00141
00142
00143 u_int32_t qdelay = (qlen + 1) * edge->info().params_.delay_ / 1000;
00144 u_int32_t bwdelay = 0;
00145 if (edge->info().params_.bw_ != 0) {
00146
00147 bwdelay = qsize / edge->info().params_.bw_;
00148 }
00149
00150 u_int32_t delay = qdelay + bwdelay;
00151 log_debug_p("/dtn/route/graph", "weight of edge %s=%u "
00152 "(qlen %u delay %u qdelay %u qsize %u bw %u bwdelay %u)",
00153 edge->info().id_.c_str(), delay,
00154 qlen, edge->info().params_.delay_, qdelay,
00155 qsize, edge->info().params_.bw_, bwdelay);
00156
00157
00158
00159
00160
00161
00162 return delay;
00163 }
00164
00165 DTLSRRouter* router_;
00166 };
00167
00168
00169 DTLSRRouter::DTLSRRouter()
00170 : TableBasedRouter("DTLSRRouter", "dtlsr"),
00171 announce_tag_("dtlsr"),
00172 announce_eid_("dtn://*/dtlsr?*"),
00173 current_lsas_("DTLSRRouter::current_lsas"),
00174 periodic_lsa_timer_(this),
00175 delayed_lsa_timer_(this)
00176 {
00177
00178 config_.add_nexthop_routes_ = false;
00179 }
00180
00181
00182 void
00183 DTLSRRouter::initialize()
00184 {
00185 TableBasedRouter::initialize();
00186
00187 const EndpointID& local_eid = BundleDaemon::instance()->local_eid();
00188
00189 if (local_eid.scheme_str() != "dtn") {
00190 log_crit("cannot use DTLSR with a local eid not in the 'dtn' scheme");
00191 exit(1);
00192 }
00193
00194 local_node_ = graph_.add_node(local_eid.str(), NodeInfo());
00195
00196 EndpointIDPattern admin_eid = local_eid;
00197 admin_eid.append_service_tag(announce_tag_);
00198 reg_ = new Reg(this, admin_eid);
00199
00200 log_info("initializing: local_eid %s weight_fn %s",
00201 local_eid.c_str(),
00202 DTLSRConfig::weight_fn_to_str(config()->weight_fn_));
00203
00204 switch (config()->weight_fn_) {
00205 case DTLSRConfig::COST:
00206 weight_fn_ = new CostWeightFn();
00207 break;
00208
00209 case DTLSRConfig::DELAY:
00210 weight_fn_ = new DelayWeightFn();
00211 break;
00212
00213 case DTLSRConfig::ESTIMATED_DELAY:
00214 weight_fn_ = new EstimatedDelayWeightFn(this);
00215 break;
00216 }
00217
00218 if (config()->lsa_interval_ != 0) {
00219 periodic_lsa_timer_.set_interval(config()->lsa_interval_ * 1000);
00220 periodic_lsa_timer_.schedule_in(config()->lsa_interval_ * 1000);
00221 }
00222 }
00223
00224
00225 void
00226 DTLSRRouter::get_routing_state(oasys::StringBuffer* buf)
00227 {
00228
00229
00230
00231 buf->appendf("DTLSR Routing Graph:\n*%p", &graph_);
00232 buf->appendf("Current routing table:\n");
00233 TableBasedRouter::get_routing_state(buf);
00234 }
00235
00236
00237 bool
00238 DTLSRRouter::can_delete_bundle(const BundleRef& bundle)
00239 {
00240 if (! TableBasedRouter::can_delete_bundle(bundle)) {
00241 return false;
00242 }
00243
00244 if (current_lsas_.contains(bundle)) {
00245 log_debug("can_delete_bundle(%u): current lsa", bundle->bundleid());
00246 return false;
00247 }
00248
00249 return true;
00250 }
00251
00252
00253 void
00254 DTLSRRouter::delete_bundle(const BundleRef& bundle)
00255 {
00256 TableBasedRouter::delete_bundle(bundle);
00257
00258 if (current_lsas_.contains(bundle))
00259 {
00260 log_crit("deleting bundle id %u whilea still on current lsas list",
00261 bundle->bundleid());
00262 current_lsas_.erase(bundle);
00263 }
00264 }
00265
00266
00267 void
00268 DTLSRRouter::handle_link_created(LinkCreatedEvent* e)
00269 {
00270
00271
00272
00273 invalidate_routes();
00274 recompute_routes();
00275 TableBasedRouter::handle_link_created(e);
00276 }
00277
00278
00279 void
00280 DTLSRRouter::handle_bundle_received(BundleReceivedEvent* e)
00281 {
00282
00283
00284
00285
00286 TableBasedRouter::handle_bundle_received(e);
00287 }
00288
00289
00290 void
00291 DTLSRRouter::handle_bundle_expired(BundleExpiredEvent* e)
00292 {
00293 Bundle* bundle = e->bundleref_.object();
00294
00295
00296
00297
00298
00299
00300 oasys::ScopeLock l(current_lsas_.lock(),
00301 "DTLSRRouter::handle_bundle_expired");
00302
00303 if (current_lsas_.contains(bundle))
00304 {
00305 log_notice("current lsa for %s expired... kicking links",
00306 bundle->source().c_str());
00307 handle_lsa_expired(bundle);
00308 current_lsas_.erase(bundle);
00309 }
00310
00311 TableBasedRouter::handle_bundle_expired(e);
00312 }
00313
00314
00315 void
00316 DTLSRRouter::handle_contact_up(ContactUpEvent* e)
00317 {
00318 const LinkRef& link = e->contact_->link();
00319 if (link->remote_eid() == EndpointID::NULL_EID()) {
00320 log_warn("can't handle link %s: no remote endpoint id",
00321 link->name());
00322 return;
00323 }
00324
00325 EdgeInfo ei(link->name());
00326
00327 ei.params_.cost_ = link->params().cost_;
00328
00329 RoutingGraph::Node* remote_node =
00330 graph_.find_node(link->remote_eid().str());
00331
00332 if (remote_node == NULL) {
00333 remote_node = graph_.add_node(link->remote_eid().str(), NodeInfo());
00334 }
00335
00336 RoutingGraph::Edge* edge = graph_.find_edge(local_node_, remote_node, ei);
00337 if (edge == NULL) {
00338 edge = graph_.add_edge(local_node_, remote_node, ei);
00339 } else {
00340 edge->mutable_info().params_.state_ = LinkParams::LINK_UP;
00341 }
00342
00343
00344 invalidate_routes();
00345 recompute_routes();
00346
00347
00348 schedule_lsa();
00349
00350
00351 TableBasedRouter::handle_contact_up(e);
00352 }
00353
00354
00355 void
00356 DTLSRRouter::handle_contact_down(ContactDownEvent* e)
00357 {
00358 const LinkRef& link = e->contact_->link();
00359
00360 RoutingGraph::Node* remote_node =
00361 graph_.find_node(link->remote_eid().str());
00362
00363 if (remote_node == NULL) {
00364 log_err("contact down event for link %s: node not in routing graph",
00365 link->name());
00366 return;
00367 }
00368
00369 RoutingGraph::Edge* edge = NULL;
00370 RoutingGraph::EdgeVector::const_iterator iter;
00371 for (iter = local_node_->out_edges().begin();
00372 iter != local_node_->out_edges().end(); ++iter)
00373 {
00374 if ((*iter)->info().id_ == link->name_str()) {
00375 edge = *iter;
00376 break;
00377 }
00378 }
00379
00380 if (edge == NULL) {
00381 log_err("handle_contact_down: can't find link *%p", link.object());
00382 return;
00383 }
00384
00385 edge->mutable_info().params_.state_ = LinkParams::LINK_DOWN;
00386
00387
00388 invalidate_routes();
00389 recompute_routes();
00390
00391
00392 schedule_lsa();
00393
00394 if (! config()->keep_down_links_) {
00395 remove_edge(edge);
00396 }
00397
00398 TableBasedRouter::handle_contact_down(e);
00399 }
00400
00401
00402 void
00403 DTLSRRouter::handle_link_deleted(LinkDeletedEvent* e)
00404 {
00405 TableBasedRouter::handle_link_deleted(e);
00406 NOTREACHED;
00407
00408
00409
00410 RoutingGraph::EdgeVector::const_iterator iter;
00411 for (iter = local_node_->out_edges().begin();
00412 iter != local_node_->out_edges().end(); ++iter)
00413 {
00414 if ((*iter)->info().id_ == e->link_->name()) {
00415 remove_edge(*iter);
00416 return;
00417 }
00418 }
00419
00420 log_err("handle_link_deleted: can't find link *%p", e->link_.object());
00421 }
00422
00423
00424 void
00425 DTLSRRouter::handle_registration_added(RegistrationAddedEvent* event)
00426 {
00427 Registration* reg = event->registration_;
00428 const EndpointID& local_eid = BundleDaemon::instance()->local_eid();
00429
00430 TableBasedRouter::handle_registration_added(event);
00431
00432
00433
00434
00435
00436
00437
00438 if (reg->endpoint().subsume(local_eid)) {
00439 return;
00440 }
00441
00442 std::string eid;
00443 if (reg->session_flags() == 0)
00444 {
00445 eid = reg->endpoint().str();
00446 }
00447 else if (reg->session_flags() & Session::CUSTODY)
00448 {
00449 eid = std::string("dtn-session:") + reg->endpoint().str();
00450 }
00451 else
00452 {
00453 return;
00454 }
00455
00456 RoutingGraph::Node* node = graph_.find_node(eid);
00457 if (node == NULL) {
00458 log_debug("handle_registration added: adding new graph node for %s",
00459 eid.c_str());
00460 node = graph_.add_node(eid, NodeInfo());
00461 }
00462
00463 EdgeInfo ei(std::string("reg-") + eid);
00464 ei.is_registration_ = true;
00465 ei.params_.bw_ = 0xffffffff;
00466
00467 RoutingGraph::Edge* edge = graph_.find_edge(local_node_, node, ei);
00468 if (edge == NULL) {
00469 log_debug("handle_registration added: adding new edge node for %s",
00470 ei.id_.c_str());
00471 edge = graph_.add_edge(local_node_, node, ei);
00472
00473
00474 schedule_lsa();
00475 }
00476 }
00477
00478
00479 void
00480 DTLSRRouter::remove_edge(RoutingGraph::Edge* edge)
00481 {
00482 log_debug("remove_edge %s", edge->info().id_.c_str());
00483 bool ok = graph_.del_edge(local_node_, edge);
00484 ASSERT(ok);
00485 }
00486
00487
00488 bool
00489 DTLSRRouter::time_to_age_routes()
00490 {
00491 u_int32_t elapsed = last_update_.elapsed_ms() / 1000;
00492 if (elapsed > config()->aging_interval_) {
00493 return true;
00494 }
00495 return false;
00496 }
00497
00498
00499 void
00500 DTLSRRouter::invalidate_routes()
00501 {
00502 log_debug("invalidating routes");
00503 last_update_.sec_ = 0;
00504 }
00505
00506
00507 bool
00508 DTLSRRouter::is_dynamic_route(RouteEntry* entry)
00509 {
00510 if (entry->info() == NULL) {
00511 return false;
00512 }
00513
00514 RouteInfo* info = dynamic_cast<RouteInfo*>(entry->info());
00515 if (info != NULL) {
00516 return true;
00517 }
00518
00519 return false;
00520 }
00521
00522
00523 void
00524 DTLSRRouter::recompute_routes()
00525 {
00526
00527
00528
00529
00530
00531
00532
00533
00534 log_debug("recomputing all routes");
00535 last_update_.get_time();
00536
00537 route_table_->del_matching_entries(is_dynamic_route);
00538
00539
00540
00541 RoutingGraph::NodeVector::const_iterator iter;
00542 for (iter = graph_.nodes().begin(); iter != graph_.nodes().end(); ++iter) {
00543 const RoutingGraph::Node* dest = *iter;
00544
00545 if (dest == local_node_) {
00546 continue;
00547 }
00548
00549 EndpointIDPattern dest_eid(dest->id());
00550 dest_eid.append_service_tag("*");
00551 ASSERT(dest_eid.valid());
00552
00553
00554
00555
00556 RoutingGraph::Edge* edge = graph_.best_next_hop(local_node_, dest,
00557 weight_fn_);
00558 if (edge == NULL) {
00559
00560 continue;
00561 }
00562
00563 ContactManager* cm = BundleDaemon::instance()->contactmgr();
00564 LinkRef link = cm->find_link(edge->info().id_.c_str());
00565 if (link == NULL) {
00566
00567
00568
00569 log_debug("link %s not in local link table... ignoring it",
00570 edge->info().id_.c_str());
00571 continue;
00572 }
00573
00574 log_debug("recompute_routes: adding route for %s to link %s",
00575 dest_eid.c_str(), link->name());
00576
00577
00578 RouteEntry* e = new RouteEntry(dest_eid, link);
00579 e->set_info(new RouteInfo(edge));
00580 route_table_->add_entry(e);
00581 }
00582
00583
00584 handle_changed_routes();
00585 }
00586
00587
00588 DTLSRRouter::Reg::Reg(DTLSRRouter* router,
00589 const EndpointIDPattern& eid)
00590 : Registration(DTLSR_REGID, eid, Registration::DEFER,
00591 0, 0),
00592
00593 router_(router)
00594 {
00595 logpathf("%s/reg", router->logpath()),
00596 BundleDaemon::post(new RegistrationAddedEvent(this, EVENTSRC_ADMIN));
00597 }
00598
00599
00600 void
00601 DTLSRRouter::Reg::deliver_bundle(Bundle* bundle)
00602 {
00603
00604 if (bundle->source() == BundleDaemon::instance()->local_eid()) {
00605 log_info("ignoring bundle sent by self");
00606 return;
00607 }
00608
00609 u_char type;
00610 bundle->payload().read_data(0, 1, &type);
00611
00612 if (type == DTLSR::MSG_LSA) {
00613 log_info("got LSA bundle *%p",bundle);
00614
00615 LSA lsa;
00616 if (!DTLSR::parse_lsa_bundle(bundle, &lsa)) {
00617 log_warn("error parsing LSA");
00618 goto bail;
00619 }
00620
00621 router_->handle_lsa(bundle, &lsa);
00622 } else {
00623 log_err("unknown message type %d", type);
00624 }
00625
00626 bail:
00627 BundleDaemon::post_at_head(new BundleDeliveredEvent(bundle, this));
00628 }
00629
00630
00631 bool
00632 DTLSRRouter::update_current_lsa(RoutingGraph::Node* node,
00633 Bundle* bundle, u_int32_t seqno)
00634 {
00635 bool found_stale_lsa = false;
00636 if (seqno <= node->info().last_lsa_seqno_ &&
00637 bundle->creation_ts().seconds_ < node->info().last_lsa_creation_ts_)
00638 {
00639 log_info("update_current_lsa: "
00640 "ignoring stale LSA (seqno %u <= last %u, "
00641 "creation_ts %u <= last %u)",
00642 seqno, node->info().last_lsa_seqno_,
00643 bundle->creation_ts().seconds_,
00644 node->info().last_lsa_creation_ts_);
00645
00646
00647 bundle->fwdlog()->add_entry(EndpointIDPattern::WILDCARD_EID(),
00648 ForwardingInfo::FORWARD_ACTION,
00649 ForwardingInfo::SUPPRESSED);
00650
00651 return false;
00652 }
00653 else
00654 {
00655 log_info("update_current_lsa: "
00656 "got new LSA (seqno %u > last %u || "
00657 "creation_ts %u > last %u)",
00658 seqno, node->info().last_lsa_seqno_,
00659 bundle->creation_ts().seconds_,
00660 node->info().last_lsa_creation_ts_);
00661 }
00662
00663 oasys::ScopeLock l(current_lsas_.lock(),
00664 "DTLSRRouter::update_current_lsa");
00665 for (BundleList::iterator iter = current_lsas_.begin();
00666 iter != current_lsas_.end(); ++iter)
00667 {
00668 if ((*iter)->source() == node->id()) {
00669
00670
00671
00672 BundleRef stale_lsa("DTLSRRouter::update_current_lsa");
00673 stale_lsa = *iter;
00674
00675 current_lsas_.erase(iter);
00676
00677 log_debug("cancelling pending transmissions for *%p",
00678 stale_lsa.object());
00679
00680 stale_lsa->fwdlog()->add_entry(EndpointIDPattern::WILDCARD_EID(),
00681 ForwardingInfo::FORWARD_ACTION,
00682 ForwardingInfo::SUPPRESSED);
00683
00684 BundleDaemon::post_at_head(
00685 new BundleDeleteRequest(stale_lsa.object(),
00686 BundleProtocol::REASON_NO_ADDTL_INFO));
00687 found_stale_lsa = true;
00688
00689
00690
00691
00692
00693 if (node->info().last_lsa_seqno_ == 0) {
00694 NOTREACHED;
00695 }
00696 break;
00697 }
00698 }
00699
00700 if (node->info().last_lsa_seqno_ == 0) {
00701 ASSERT(!found_stale_lsa);
00702 log_info("update_current_lsa: "
00703 "first LSA from %s (seqno %u)",
00704 node->id().c_str(), seqno);
00705 } else {
00706 log_info("update_current_lsa: "
00707 "replaced %s LSA from %s (seqno %u) with latest (%u)",
00708 found_stale_lsa ? "stale" : "expired",
00709 node->id().c_str(), node->info().last_lsa_seqno_, seqno);
00710 }
00711
00712 node->mutable_info().last_lsa_seqno_ = seqno;
00713 node->mutable_info().last_lsa_creation_ts_ = bundle->creation_ts().seconds_;
00714 current_lsas_.push_back(bundle);
00715 return true;
00716 }
00717
00718
00719 void
00720 DTLSRRouter::handle_lsa(Bundle* bundle, LSA* lsa)
00721 {
00722
00723
00724 std::string lsa_area = bundle->dest().uri().query_value("area");
00725 if (config()->area_ != lsa_area) {
00726 log_debug("handle_lsa: ignoring LSA since area %s != local area %s",
00727 lsa_area.c_str(), config()->area_.c_str());
00728
00729 bundle->fwdlog()->add_entry(EndpointIDPattern::WILDCARD_EID(),
00730 ForwardingInfo::FORWARD_ACTION,
00731 ForwardingInfo::SUPPRESSED);
00732 return;
00733 }
00734
00735 const EndpointID& source = bundle->source();
00736
00737 RoutingGraph::Node* a = graph_.find_node(source.str());
00738 if (a == NULL) {
00739 log_debug("handle_lsa: adding new source node %s",
00740 source.c_str());
00741 a = graph_.add_node(source.str(), NodeInfo());
00742 }
00743
00744 if (! update_current_lsa(a, bundle, lsa->seqno_)) {
00745 return;
00746 }
00747
00748
00749 ForwardingInfo info;
00750 if (bundle->fwdlog()->get_latest_entry(ForwardingInfo::RECEIVED, &info))
00751 {
00752 log_debug("handle_lsa: suppressing transmission back to %s",
00753 info.remote_eid().c_str());
00754 bundle->fwdlog()->add_entry(info.remote_eid(),
00755 ForwardingInfo::FORWARD_ACTION,
00756 ForwardingInfo::SUPPRESSED);
00757 }
00758
00759
00760
00761
00762
00763 for (LinkStateVec::iterator iter = lsa->links_.begin();
00764 iter != lsa->links_.end(); ++iter)
00765 {
00766 LinkState* ls = &(*iter);
00767
00768
00769
00770
00771 if (a == local_node_) {
00772 LinkRef link("DTLSRRouter::handle_lsa");
00773 link = BundleDaemon::instance()->contactmgr()->
00774 find_link(ls->id_.c_str());
00775 if (link == NULL) {
00776 log_warn("local link %s in LSA but no longer exists, ignoring...",
00777 ls->id_.c_str());
00778 continue;
00779 }
00780 }
00781
00782
00783 RoutingGraph::Node* b = graph_.find_node(ls->dest_.str());
00784 if (!b) {
00785 log_debug("handle_lsa: %s adding new dest node %s",
00786 source.c_str(), ls->dest_.c_str());
00787 b = graph_.add_node(ls->dest_.str(), NodeInfo());
00788 }
00789
00790
00791 RoutingGraph::Edge *e = NULL;
00792 RoutingGraph::EdgeVector::const_iterator ei;
00793 for (ei = a->out_edges().begin(); ei != a->out_edges().end(); ++ei) {
00794 if ((*ei)->info().id_ == ls->id_) {
00795 e = *ei;
00796 break;
00797 }
00798 }
00799
00800 if (e == NULL) {
00801 e = graph_.add_edge(a, b, EdgeInfo(ls->id_, ls->params_));
00802
00803 log_debug("handle_lsa: added new edge %s from %s -> %s",
00804 oasys::InlineFormatter<EdgeInfo>().format(e->info()),
00805 a->id().c_str(), b->id().c_str());
00806 } else {
00807 e->mutable_info().params_ = ls->params_;
00808
00809 log_debug("handle_lsa: updated edge %s from %s -> %s",
00810 oasys::InlineFormatter<EdgeInfo>().format(e->info()),
00811 a->id().c_str(), b->id().c_str());
00812 }
00813
00814
00815 e->mutable_info().last_update_.get_time();
00816 }
00817
00818 recompute_routes();
00819 }
00820
00821
00822 void
00823 DTLSRRouter::handle_lsa_expired(Bundle* bundle)
00824 {
00825
00826
00827
00828 (void)bundle;
00829
00830
00831
00832
00833
00834
00835
00836
00837
00838
00839
00840
00841
00842
00843 }
00844
00845
00846 void
00847 DTLSRRouter::generate_link_state(LinkState* ls,
00848 RoutingGraph::Edge* edge,
00849 const LinkRef& link)
00850 {
00851 ls->dest_.assign(edge->dest()->id());
00852 ls->id_.assign(edge->info().id_);
00853 ls->params_ = edge->info().params_;
00854
00855
00856
00857 if (link != NULL) {
00858 ls->params_.qcount_ = link->bundles_queued();
00859 ls->params_.qsize_ = link->bytes_queued();
00860 }
00861
00862 if (edge->info().last_update_.sec_ != 0) {
00863 ls->elapsed_ = edge->info().last_update_.elapsed_ms();
00864 } else {
00865 ls->elapsed_ = 0;
00866 }
00867 edge->mutable_info().last_update_.get_time();
00868 }
00869
00870
00871 void
00872 DTLSRRouter::TransmitLSATimer::timeout(const struct timeval& now)
00873 {
00874 (void)now;
00875 router_->send_lsa();
00876 if (interval_ != 0) {
00877 schedule_in(interval_);
00878 }
00879 }
00880
00881
00882 void
00883 DTLSRRouter::schedule_lsa()
00884 {
00885 if (delayed_lsa_timer_.pending()) {
00886 log_debug("schedule_lsa: delayed LSA transmission already pending");
00887 return;
00888 }
00889
00890 u_int elapsed = (oasys::Time::now() - last_lsa_transmit_).sec_;
00891 if (elapsed > config()->min_lsa_interval_)
00892 {
00893 log_debug("schedule_lsa: %u seconds since last LSA transmission, "
00894 "sending one immediately", elapsed);
00895 send_lsa();
00896 }
00897 else
00898 {
00899 u_int delay = std::min(config()->min_lsa_interval_,
00900 config()->min_lsa_interval_ - elapsed);
00901 log_debug("schedule_lsa: %u seconds since last LSA transmission, "
00902 "min interval %u, delaying LSA for %u seconds",
00903 elapsed, config()->min_lsa_interval_, delay);
00904 delayed_lsa_timer_.schedule_in(delay * 1000);
00905 }
00906 }
00907
00908
00909 void
00910 DTLSRRouter::send_lsa()
00911 {
00912 char tmp[64]; (void)tmp;
00913 LSA lsa;
00914
00915
00916
00917 lsa.seqno_ = local_node_->info().last_lsa_seqno_ + 1;
00918
00919 RoutingGraph::EdgeVector::iterator ei;
00920 for (ei = local_node_->out_edges().begin();
00921 ei != local_node_->out_edges().end();
00922 ++ei)
00923 {
00924 LinkState ls;
00925 LinkRef link("DTLSRRouter::send_lsa");
00926
00927
00928
00929
00930 if (! (*ei)->info().is_registration_) {
00931 link = BundleDaemon::instance()->contactmgr()->
00932 find_link((*ei)->info().id_.c_str());
00933 ASSERT(link != NULL);
00934 }
00935
00936 generate_link_state(&ls, *ei, link);
00937 lsa.links_.push_back(ls);
00938 }
00939
00940 log_debug("send_lsa: generated %zu link states for local node",
00941 lsa.links_.size());
00942
00943 Bundle* bundle = new TempBundle();
00944
00945 if (config()->area_ != "") {
00946 snprintf(tmp, sizeof(tmp), "dtn://*/%s?area=%s;lsa_seqno=%u",
00947 announce_tag_, config()->area_.c_str(), lsa.seqno_);
00948 } else {
00949 snprintf(tmp, sizeof(tmp), "dtn://*/%s?lsa_seqno=%u",
00950 announce_tag_, lsa.seqno_);
00951 }
00952 bundle->mutable_dest()->assign(tmp);
00953
00954 bundle->mutable_source()->assign(BundleDaemon::instance()->local_eid());
00955 bundle->mutable_replyto()->assign(EndpointID::NULL_EID());
00956 bundle->mutable_custodian()->assign(EndpointID::NULL_EID());
00957 bundle->set_expiration(config()->lsa_lifetime_);
00958 bundle->set_singleton_dest(false);
00959 DTLSR::format_lsa_bundle(bundle, &lsa);
00960
00961 update_current_lsa(local_node_, bundle, lsa.seqno_);
00962
00963 log_debug("send_lsa: formatted LSA bundle *%p", bundle);
00964
00965
00966
00967 BundleDaemon::post_at_head(new BundleReceivedEvent(bundle, EVENTSRC_ROUTER));
00968
00969 last_lsa_transmit_.get_time();
00970 }
00971
00972 }
00973