@Override
  protected void handle_contact_up(ContactUpEvent event) {
    Link link = event.contact().link();
    assert (link != null) : "TabledBasedRouter: handle_contact_up : link is null";
    assert (!link.isdeleted()) : "TabledBasedRouter: handle_contact_up : link is deleted";

    if (!link.isopen()) {
      Log.e(
          TAG,
          String.format("contact up(link %s): event delivered but link not open", link.name()));
    }

    add_nexthop_route(link);
    check_next_hop(link);

    // "check if there's a pending reroute timer on the link, and if
    // so, cancel it.
    //
    // note that there's a possibility that a link just bounces
    // between up and down states but can't ever really send a bundle
    // (or part of one), which we don't handle here since we can't
    // distinguish that case from one in which the CL is actually
    // sending data, just taking a long time to do so." [DTN2]

    RerouteTimer reroute_timer = reroute_timers_.get(link.name());
    if (reroute_timer != null) {
      Log.d(TAG, String.format("link %s reopened, cancelling reroute timer", link.name()));
      reroute_timers_.remove(link.name());
      reroute_timer.cancel();
    }
  }
  @Override
  protected void handle_link_deleted(LinkDeletedEvent event) {
    Link link = event.link();
    assert (link != null) : "TableBasedRouter: handle_link_deleted: link is null";

    route_table_.del_entries_for_nexthop(link);

    RerouteTimer t = reroute_timers_.get(link.name());
    if (t != null) {
      Log.d(TAG, String.format("link %s deleted, cancelling reroute timer", link.name()));
      reroute_timers_.remove(link.name());
      t.cancel();
    }
  }