fboss/agent/lldp/LinkNeighborDB.cpp (103 lines of code) (raw):

// Copyright 2004-present Facebook. All Rights Reserved. #include "fboss/agent/lldp/LinkNeighborDB.h" using std::lock_guard; using std::mutex; using std::vector; using std::chrono::steady_clock; namespace facebook::fboss { LinkNeighborDB::NeighborKey::NeighborKey(const LinkNeighbor& neighbor) : chassisIdType_(neighbor.getChassisIdType()), portIdType_(neighbor.getPortIdType()), chassisId_(neighbor.getChassisId()), portId_(neighbor.getPortId()) {} bool LinkNeighborDB::NeighborKey::operator<(const NeighborKey& other) const { if (chassisIdType_ < other.chassisIdType_) { return true; } else if (chassisIdType_ > other.chassisIdType_) { return false; } if (portIdType_ < other.portIdType_) { return true; } else if (portIdType_ > other.portIdType_) { return false; } if (chassisId_ < other.chassisId_) { return true; } else if (chassisId_ > other.chassisId_) { return false; } if (portId_ < other.portId_) { return true; } else if (portId_ > other.portId_) { return false; } return false; } bool LinkNeighborDB::NeighborKey::operator==(const NeighborKey& other) const { return ( chassisIdType_ == other.chassisIdType_ && portIdType_ == other.portIdType_ && chassisId_ == other.chassisId_ && portId_ == other.portId_); } LinkNeighborDB::LinkNeighborDB() {} void LinkNeighborDB::update(const LinkNeighbor& neighbor) { lock_guard<mutex> guard(mutex_); // Go ahead and prune expired neighbors each time we get updated. pruneLocked(steady_clock::now()); auto it = byLocalPort_.find(neighbor.getLocalPort()); if (it == byLocalPort_.end()) { // This is the first time we have seen data for this port. auto ret = byLocalPort_.emplace(neighbor.getLocalPort(), NeighborMap()); it = ret.first; } NeighborKey key(neighbor); // It would be nicer to use insert_or_assign() once we move to C++17 it->second[key] = neighbor; } vector<LinkNeighbor> LinkNeighborDB::getNeighbors() { vector<LinkNeighbor> results; lock_guard<mutex> guard(mutex_); for (const auto& portEntry : byLocalPort_) { for (const auto& entry : portEntry.second) { results.push_back(entry.second); } } return results; } vector<LinkNeighbor> LinkNeighborDB::getNeighbors(PortID port) { vector<LinkNeighbor> results; lock_guard<mutex> guard(mutex_); auto it = byLocalPort_.find(port); if (it != byLocalPort_.end()) { for (const auto& entry : it->second) { results.push_back(entry.second); } } return results; } int LinkNeighborDB::pruneExpiredNeighbors() { lock_guard<mutex> guard(mutex_); return pruneLocked(steady_clock::now()); } int LinkNeighborDB::pruneExpiredNeighbors(steady_clock::time_point now) { lock_guard<mutex> guard(mutex_); return pruneLocked(now); } void LinkNeighborDB::portDown(PortID port) { lock_guard<mutex> guard(mutex_); // Port went down, prune lldp entries for that port byLocalPort_.erase(port); } int LinkNeighborDB::pruneLocked(steady_clock::time_point now) { // We just do a linear scan for now. // // We could maintain a priority queue of entries by expiration time, // to make this scanning faster. However, we don't expect the number of // neighbors to be very large, so the extra complexity isn't worth // implementing right now. int count = 0; for (auto& portEntry : byLocalPort_) { // Advance the iterator manually to avoid make sure we don't // have invalid iterators to erased elements. auto& map = portEntry.second; auto it = map.begin(); while (it != map.end()) { auto current = it; ++it; if (current->second.isExpired(now)) { map.erase(current); } else { count++; } } } return count; } } // namespace facebook::fboss