/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ /* * Copyright (c) 2014-2022, Regents of the University of California, * Arizona Board of Regents, * Colorado State University, * University Pierre & Marie Curie, Sorbonne University, * Washington University in St. Louis, * Beijing Institute of Technology, * The University of Memphis. * * This file is part of NFD (Named Data Networking Forwarding Daemon). * See AUTHORS.md for complete list of NFD authors and contributors. * * NFD is free software: you can redistribute it and/or modify it under the terms * of the GNU General Public License as published by the Free Software Foundation, * either version 3 of the License, or (at your option) any later version. * * NFD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR * PURPOSE. See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along with * NFD, e.g., in COPYING.md file. If not, see . */ #include "rib-entry.hpp" #include "common/logger.hpp" #include namespace nfd::rib { NFD_LOG_INIT(RibEntry); static bool compareFaceIdAndOrigin(const Route& lhs, const Route& rhs) { return lhs.faceId == rhs.faceId && lhs.origin == rhs.origin; } RibEntry::RouteList::iterator RibEntry::findRoute(const Route& route) { return std::find_if(begin(), end(), [&] (const auto& r) { return compareFaceIdAndOrigin(r, route); }); } RibEntry::RouteList::const_iterator RibEntry::findRoute(const Route& route) const { return std::find_if(begin(), end(), [&] (const auto& r) { return compareFaceIdAndOrigin(r, route); }); } std::pair RibEntry::insertRoute(const Route& route) { auto it = findRoute(route); if (it == end()) { if (route.flags & ndn::nfd::ROUTE_FLAG_CAPTURE) { m_nRoutesWithCaptureSet++; } m_routes.push_back(route); return {std::prev(m_routes.end()), true}; } return {it, false}; } void RibEntry::eraseRoute(const Route& route) { auto it = findRoute(route); eraseRoute(it); } bool RibEntry::hasRoute(const Route& route) { auto it = findRoute(route); return it != end(); } bool RibEntry::hasFaceId(uint64_t faceId) const { auto it = std::find_if(begin(), end(), [faceId] (const auto& r) { return r.faceId == faceId; }); return it != end(); } size_t RibEntry::getNRoutes() const { return m_routes.size(); } void RibEntry::addChild(shared_ptr child) { BOOST_ASSERT(!child->getParent()); child->setParent(this->shared_from_this()); m_children.push_back(std::move(child)); } void RibEntry::removeChild(shared_ptr child) { BOOST_ASSERT(child->getParent().get() == this); child->setParent(nullptr); m_children.remove(child); } RibEntry::RouteList::iterator RibEntry::eraseRoute(RouteList::iterator route) { if (route != m_routes.end()) { if (route->flags & ndn::nfd::ROUTE_FLAG_CAPTURE) { m_nRoutesWithCaptureSet--; } // Cancel any scheduled event NFD_LOG_TRACE("Cancelling expiration event: " << route->getExpirationEvent()); route->cancelExpirationEvent(); return m_routes.erase(route); } return m_routes.end(); } void RibEntry::addInheritedRoute(const Route& route) { m_inheritedRoutes.push_back(route); } void RibEntry::removeInheritedRoute(const Route& route) { m_inheritedRoutes.remove_if([id = route.faceId] (const auto& r) { return r.faceId == id; }); } RibEntry::RouteList::const_iterator RibEntry::findInheritedRoute(const Route& route) const { return std::find_if(m_inheritedRoutes.begin(), m_inheritedRoutes.end(), [id = route.faceId] (const auto& r) { return r.faceId == id; }); } bool RibEntry::hasInheritedRoute(const Route& route) const { return findInheritedRoute(route) != m_inheritedRoutes.end(); } bool RibEntry::hasCapture() const { return m_nRoutesWithCaptureSet > 0; } bool RibEntry::hasChildInheritOnFaceId(uint64_t faceId) const { for (const Route& route : m_routes) { if (route.faceId == faceId && (route.flags & ndn::nfd::ROUTE_FLAG_CHILD_INHERIT)) { return true; } } return false; } const Route* RibEntry::getRouteWithLowestCostByFaceId(uint64_t faceId) const { const Route* candidate = nullptr; for (const Route& route : m_routes) { // Matching face ID if (route.faceId == faceId) { // If this is the first route with this Face ID found if (candidate == nullptr) { candidate = &route; } else if (route.cost < candidate->cost) { // Found a route with a lower cost candidate = &route; } } } return candidate; } const Route* RibEntry::getRouteWithSecondLowestCostByFaceId(uint64_t faceId) const { std::vector matches; // Copy routes which have faceId for (const Route& route : m_routes) { if (route.faceId == faceId) { matches.push_back(&route); } } // If there are less than 2 routes, there is no second lowest if (matches.size() < 2) { return nullptr; } // Get second lowest cost std::nth_element(matches.begin(), matches.begin() + 1, matches.end(), [] (const Route* lhs, const Route* rhs) { return lhs->cost < rhs->cost; }); return matches.at(1); } const Route* RibEntry::getRouteWithLowestCostAndChildInheritByFaceId(uint64_t faceId) const { const Route* candidate = nullptr; for (const Route& route : m_routes) { // Correct face ID and Child Inherit flag set if (route.faceId == faceId && (route.flags & ndn::nfd::ROUTE_FLAG_CHILD_INHERIT) == ndn::nfd::ROUTE_FLAG_CHILD_INHERIT) { // If this is the first route with this Face ID found if (candidate == nullptr) { candidate = &route; } else if (route.cost < candidate->cost) { // Found a route with a lower cost candidate = &route; } } } return candidate; } ndn::PrefixAnnouncement RibEntry::getPrefixAnnouncement(time::milliseconds minExpiration, time::milliseconds maxExpiration) const { const Route* bestAnnRoute = nullptr; auto entryExpiry = time::steady_clock::time_point::min(); for (const Route& route : *this) { if (route.expires) { entryExpiry = std::max(entryExpiry, *route.expires); if (route.announcement) { if (bestAnnRoute == nullptr || *route.expires > *bestAnnRoute->expires) { bestAnnRoute = &route; } } } else { entryExpiry = time::steady_clock::time_point::max(); } } if (bestAnnRoute != nullptr) { return *bestAnnRoute->announcement; } ndn::PrefixAnnouncement ann; ann.setAnnouncedName(m_name); ann.setExpiration(std::clamp( time::duration_cast(entryExpiry - time::steady_clock::now()), minExpiration, maxExpiration)); return ann; } std::ostream& operator<<(std::ostream& os, const RibEntry& entry) { os << "RibEntry {\n" << " Name: " << entry.getName() << "\n"; for (const Route& route : entry) { os << " " << route << "\n"; } return os << "}"; } } // namespace nfd::rib