TableBasedRouter.cc

Go to the documentation of this file.
00001 /*
00002  *    Copyright 2005-2006 Intel Corporation
00003  * 
00004  *    Licensed under the Apache License, Version 2.0 (the "License");
00005  *    you may not use this file except in compliance with the License.
00006  *    You may obtain a copy of the License at
00007  * 
00008  *        http://www.apache.org/licenses/LICENSE-2.0
00009  * 
00010  *    Unless required by applicable law or agreed to in writing, software
00011  *    distributed under the License is distributed on an "AS IS" BASIS,
00012  *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
00013  *    See the License for the specific language governing permissions and
00014  *    limitations under the License.
00015  */
00016 
00017 
00018 #include "TableBasedRouter.h"
00019 #include "RouteTable.h"
00020 #include "bundling/BundleActions.h"
00021 #include "bundling/BundleDaemon.h"
00022 #include "contacts/Contact.h"
00023 #include "contacts/Link.h"
00024 
00025 namespace dtn {
00026 
00027 //----------------------------------------------------------------------
00028 TableBasedRouter::TableBasedRouter(const char* classname,
00029                                    const std::string& name)
00030     : BundleRouter(classname, name)
00031 {
00032     route_table_ = new RouteTable(name);
00033 }
00034 
00035 //----------------------------------------------------------------------
00036 TableBasedRouter::~TableBasedRouter()
00037 {
00038     delete route_table_;
00039 }
00040 
00041 //----------------------------------------------------------------------
00042 void
00043 TableBasedRouter::add_route(RouteEntry *entry)
00044 {
00045     route_table_->add_entry(entry);
00046     check_next_hop(entry->next_hop_);        
00047 }
00048 
00049 //----------------------------------------------------------------------
00050 void
00051 TableBasedRouter::del_route(const EndpointIDPattern& dest)
00052 {
00053     route_table_->del_entries(dest);
00054 }
00055 
00056 //----------------------------------------------------------------------
00057 void
00058 TableBasedRouter::handle_event(BundleEvent* event)
00059 {
00060     dispatch_event(event);
00061 }
00062 
00063 //----------------------------------------------------------------------
00064 void
00065 TableBasedRouter::handle_bundle_received(BundleReceivedEvent* event)
00066 {
00067     Bundle* bundle = event->bundleref_.object();
00068     log_debug("handle bundle received: *%p", bundle);
00069     fwd_to_matching(bundle);
00070 }
00071 
00072 //----------------------------------------------------------------------
00073 void
00074 TableBasedRouter::handle_bundle_transmit_failed(BundleTransmitFailedEvent* event)
00075 {
00076     Bundle* bundle = event->bundleref_.object();
00077     log_debug("handle bundle transmit failed: *%p", bundle);
00078     fwd_to_matching(bundle);
00079 }
00080 
00081 //----------------------------------------------------------------------
00082 void
00083 TableBasedRouter::handle_route_add(RouteAddEvent* event)
00084 {
00085     add_route(event->entry_);
00086 }
00087 
00088 //----------------------------------------------------------------------
00089 void
00090 TableBasedRouter::handle_route_del(RouteDelEvent* event)
00091 {
00092     del_route(event->dest_);
00093 }
00094 
00095 //----------------------------------------------------------------------
00096 void
00097 TableBasedRouter::handle_contact_up(ContactUpEvent* event)
00098 {
00099     check_next_hop(event->contact_->link());
00100 }
00101 
00102 //----------------------------------------------------------------------
00103 void
00104 TableBasedRouter::handle_link_available(LinkAvailableEvent* event)
00105 {
00106     check_next_hop(event->link_);
00107 }
00108 
00109 //----------------------------------------------------------------------
00110 void
00111 TableBasedRouter::handle_link_created(LinkCreatedEvent* event)
00112 {
00113     // if we're configured to do so, create a route entry for the eid
00114     // specified by the link when it connected. if it's a dtn://xyz
00115     // URI that doesn't have anything following the "hostname" part,
00116     // we add a wildcard of '/*' to match all service tags.
00117     
00118     if (config_.add_nexthop_routes_) {
00119         Link* link = event->link_;
00120         EndpointID eid = link->remote_eid();
00121         std::string eid_str = eid.str();
00122         
00123         if (eid.scheme_str() == "dtn" &&
00124             eid.ssp().length() > 2 &&
00125             eid.ssp()[0] == '/' &&
00126             eid.ssp()[1] == '/' &&
00127             eid.ssp().find('/', 2) == std::string::npos)
00128         {
00129             eid_str += std::string("/*");
00130         }
00131         
00132         RouteEntry *entry = new RouteEntry(EndpointIDPattern(eid_str), link);
00133         entry->action_ = ForwardingInfo::FORWARD_ACTION;
00134         BundleDaemon::post(new RouteAddEvent(entry));
00135     }
00136 }
00137 
00138 //----------------------------------------------------------------------
00139 void
00140 TableBasedRouter::handle_custody_timeout(CustodyTimeoutEvent* event)
00141 {
00142     // the bundle daemon should have recorded a new entry in the
00143     // forwarding log for the given link to note that custody transfer
00144     // timed out, and of course the bundle should still be in the
00145     // pending list.
00146     //
00147     // therefore, trying again to forward the bundle should match
00148     // either the previous link or any other route
00149     fwd_to_matching(event->bundle_.object());
00150 }
00151 
00152 //----------------------------------------------------------------------
00153 void
00154 TableBasedRouter::get_routing_state(oasys::StringBuffer* buf)
00155 {
00156     EndpointIDVector long_eids;
00157     buf->appendf("Route table for %s router:\n\n", name_.c_str());
00158     route_table_->dump(buf, &long_eids);
00159 
00160     if (long_eids.size() > 0) {
00161         buf->appendf("\nLong Endpoint IDs referenced above:\n");
00162         for (u_int i = 0; i < long_eids.size(); ++i) {
00163             buf->appendf("\t[%d]: %s\n", i, long_eids[i].c_str());
00164         }
00165         buf->appendf("\n");
00166     }
00167     
00168     buf->append("\nClass of Service (COS) bits:\n"
00169                 "\tB: Bulk  N: Normal  E: Expedited\n\n");
00170 }
00171 
00172 //----------------------------------------------------------------------
00173 void
00174 TableBasedRouter::fwd_to_nexthop(Bundle* bundle, RouteEntry* route)
00175 {
00176     Link* link = route->next_hop_;
00177 
00178     // if the link is open and not busy, send the bundle to it
00179     if (link->isopen() && !link->isbusy()) {
00180         log_debug("sending *%p to *%p", bundle, link);
00181         actions_->send_bundle(bundle, link,
00182                               ForwardingInfo::action_t(route->action_),
00183                               route->custody_timeout_);
00184     }
00185 
00186     // if the link is available and not open, open it
00187     else if (link->isavailable() && (!link->isopen()) && (!link->isopening())) {
00188         log_debug("opening *%p because a message is intended for it", link);
00189         actions_->open_link(link);
00190     }
00191 
00192     // otherwise, we can't do anything, so just log a bundle of
00193     // reasons why
00194     else {
00195         if (!link->isavailable()) {
00196             log_debug("can't forward *%p to *%p because link not available",
00197                       bundle, link);
00198         } else if (! link->isopen()) {
00199             log_debug("can't forward *%p to *%p because link not open",
00200                       bundle, link);
00201         } else if (link->isbusy()) {
00202             log_debug("can't forward *%p to *%p because link is busy",
00203                       bundle, link);
00204         } else {
00205             log_debug("can't forward *%p to *%p", bundle, link);
00206         }
00207     }
00208 }
00209 
00210 //----------------------------------------------------------------------
00211 bool
00212 TableBasedRouter::should_fwd(const Bundle* bundle, RouteEntry* route)
00213 {
00214     ForwardingInfo info;
00215     bool found = bundle->fwdlog_.get_latest_entry(route->next_hop_, &info);
00216 
00217     if (found) {
00218         ASSERT(info.state_ != ForwardingInfo::NONE);
00219     } else {
00220         ASSERT(info.state_ == ForwardingInfo::NONE);
00221     }
00222     
00223     if (info.state_ == ForwardingInfo::TRANSMITTED ||
00224         info.state_ == ForwardingInfo::IN_FLIGHT)
00225     {
00226         log_debug("should_fwd bundle %d: "
00227                   "skip %s due to forwarding log entry %s",
00228                   bundle->bundleid_, route->next_hop_->name(),
00229                   ForwardingInfo::state_to_str(
00230                       static_cast<ForwardingInfo::state_t>(info.state_)));
00231         return false;
00232     }
00233 
00234     if (route->action_ == ForwardingInfo::FORWARD_ACTION) {
00235         size_t count;
00236         
00237         count = bundle->fwdlog_.
00238                 get_transmission_count(ForwardingInfo::FORWARD_ACTION, true);
00239         if (count > 0) {
00240             log_debug("should_fwd bundle %d: "
00241                       "skip %s since already transmitted (count %zu)",
00242                       bundle->bundleid_, route->next_hop_->name(), count);
00243             return false;
00244         } else {
00245             log_debug("should_fwd bundle %d: "
00246                       "link %s ok since transmission count=%zu",
00247                       bundle->bundleid_, route->next_hop_->name(), count);
00248         }
00249     }
00250     
00251     if (info.state_ == ForwardingInfo::TRANSMIT_FAILED) {
00252         log_debug("should_fwd bundle %d: "
00253                   "match %s: forwarding log entry %s TRANSMIT_FAILED %d",
00254                   bundle->bundleid_, route->next_hop_->name(),
00255                   ForwardingInfo::state_to_str(
00256                       static_cast<ForwardingInfo::state_t>(info.state_)),
00257                   bundle->bundleid_);
00258         
00259     } else {
00260         log_debug("should_fwd bundle %d: "
00261                   "match %s: forwarding log entry %s",
00262                   bundle->bundleid_, route->next_hop_->name(),
00263                   ForwardingInfo::state_to_str(
00264                       static_cast<ForwardingInfo::state_t>(info.state_)));
00265     }
00266 
00267     return true;
00268 }
00269 
00270 //----------------------------------------------------------------------
00271 int
00272 TableBasedRouter::fwd_to_matching(Bundle* bundle, Link* this_link_only)
00273 {
00274     RouteEntryVec matches;
00275     RouteEntryVec::iterator iter;
00276 
00277     // get_matching only returns results that match the this_link_only
00278     // link, if it's not null
00279     route_table_->get_matching(bundle->dest_, this_link_only, &matches);
00280 
00281     // sort the list by route priority, breaking ties with the total
00282     // bytes in flight
00283     matches.sort_by_priority();
00284     
00285     int count = 0;
00286     for (iter = matches.begin(); iter != matches.end(); ++iter)
00287     {
00288         if (! should_fwd(bundle, *iter)) {
00289             continue;
00290         }
00291         
00292         fwd_to_nexthop(bundle, *iter);
00293         ++count;
00294     }
00295 
00296     log_debug("fwd_to_matching bundle id %d: %d matches",
00297               bundle->bundleid_, count);
00298     return count;
00299 }
00300 
00301 //----------------------------------------------------------------------
00302 void
00303 TableBasedRouter::check_next_hop(Link* next_hop)
00304 {
00305     log_debug("check_next_hop %s: checking pending bundle list...",
00306               next_hop->nexthop());
00307 
00308     oasys::ScopeLock l(pending_bundles_->lock(), 
00309                        "TableBasedRouter::check_next_hop");
00310     BundleList::iterator iter;
00311     for (iter = pending_bundles_->begin();
00312          iter != pending_bundles_->end();
00313          ++iter)
00314     {
00315         fwd_to_matching(*iter, next_hop);
00316     }
00317 }
00318 
00319 } // namespace dtn

Generated on Thu Jun 7 12:54:29 2007 for DTN Reference Implementation by  doxygen 1.5.1