/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/**
* Copyright (c) 2017 Alexander Afanasyev
*
* This program 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.
*
* This program 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 this program.
* If not, see .
*/
#include "arp-cache.hpp"
#include "core/utils.hpp"
#include "core/interface.hpp"
#include "simple-router.hpp"
#include
#include
namespace simple_router {
//////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////
// IMPLEMENT THIS METHOD
void
ArpCache::periodicCheckArpRequestsAndCacheEntries()
{
// printf("periodicCheckArpRequestsAndCacheEntries\n");
// FILL THIS IN
std::vector> arpRequestToRemove;
for (auto &request : m_arpRequests)
{
if (request->nTimesSent >= 5){
arpRequestToRemove.push_back(request);
for (auto &pendingPacket: request->packets){
m_router.sendICMPt3NonExisting(pendingPacket, 3, 3);
}
}
else{
request->nTimesSent++;
m_router.sendArpRequest(request->ip);
}
}
for (auto request : arpRequestToRemove){
m_arpRequests.remove(request);
}
std::vector> arpEntryToRemove;
for (auto &entry : m_cacheEntries){
if (!entry->isValid){
arpEntryToRemove.push_back(entry);
}
}
for (auto entry : arpEntryToRemove){
m_cacheEntries.remove(entry);
}
}
std::shared_ptr
ArpCache::queueRequestWithoutLock(uint32_t ip, const Buffer& packet, const std::string& iface)
{
auto request = std::find_if(m_arpRequests.begin(), m_arpRequests.end(),
[ip] (const std::shared_ptr& request) {
return (request->ip == ip);
});
if (request == m_arpRequests.end()) {
request = m_arpRequests.insert(m_arpRequests.end(), std::make_shared(ip));
}
// Add the packet to the list of packets for this request
(*request)->packets.push_back({packet, iface});
return *request;
}
std::shared_ptr
ArpCache::lookupWithoutLock(uint32_t ip)
{
for (const auto& entry : m_cacheEntries) {
if (entry->isValid && entry->ip == ip) {
return entry;
}
}
return nullptr;
}
//////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////
// You should not need to touch the rest of this code.
ArpCache::ArpCache(SimpleRouter& router)
: m_router(router)
, m_shouldStop(false)
, m_tickerThread(std::bind(&ArpCache::ticker, this))
{
}
ArpCache::~ArpCache()
{
m_shouldStop = true;
m_tickerThread.join();
}
std::shared_ptr
ArpCache::lookup(uint32_t ip)
{
std::lock_guard lock(m_mutex);
for (const auto& entry : m_cacheEntries) {
if (entry->isValid && entry->ip == ip) {
return entry;
}
}
return nullptr;
}
std::shared_ptr
ArpCache::queueRequest(uint32_t ip, const Buffer& packet, const std::string& iface)
{
std::lock_guard lock(m_mutex);
auto request = std::find_if(m_arpRequests.begin(), m_arpRequests.end(),
[ip] (const std::shared_ptr& request) {
return (request->ip == ip);
});
if (request == m_arpRequests.end()) {
request = m_arpRequests.insert(m_arpRequests.end(), std::make_shared(ip));
}
// Add the packet to the list of packets for this request
(*request)->packets.push_back({packet, iface});
return *request;
}
void
ArpCache::removeRequest(const std::shared_ptr& entry)
{
std::lock_guard lock(m_mutex);
m_arpRequests.remove(entry);
}
std::shared_ptr
ArpCache::insertArpEntry(const Buffer& mac, uint32_t ip)
{
std::lock_guard lock(m_mutex);
auto entry = std::make_shared();
entry->mac = mac;
entry->ip = ip;
entry->timeAdded = steady_clock::now();
entry->isValid = true;
m_cacheEntries.push_back(entry);
auto request = std::find_if(m_arpRequests.begin(), m_arpRequests.end(),
[ip] (const std::shared_ptr& request) {
return (request->ip == ip);
});
if (request != m_arpRequests.end()) {
return *request;
}
else {
return nullptr;
}
}
void
ArpCache::clear()
{
std::lock_guard lock(m_mutex);
m_cacheEntries.clear();
m_arpRequests.clear();
}
void
ArpCache::ticker()
{
while (!m_shouldStop) {
std::this_thread::sleep_for(std::chrono::seconds(1));
{
std::lock_guard lock(m_mutex);
auto now = steady_clock::now();
for (auto& entry : m_cacheEntries) {
if (entry->isValid && (now - entry->timeAdded > SR_ARPCACHE_TO)) {
entry->isValid = false;
}
}
periodicCheckArpRequestsAndCacheEntries();
}
}
}
std::ostream&
operator<<(std::ostream& os, const ArpCache& cache)
{
std::lock_guard lock(cache.m_mutex);
os << "\nMAC IP AGE VALID\n"
<< "-----------------------------------------------------------\n";
auto now = steady_clock::now();
for (const auto& entry : cache.m_cacheEntries) {
os << macToString(entry->mac) << " "
<< ipToString(entry->ip) << " "
<< std::chrono::duration_cast((now - entry->timeAdded)).count() << " seconds "
<< entry->isValid
<< "\n";
}
os << std::endl;
return os;
}
} // namespace simple_router