// Copyright 2018 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "portier/neighbor_cache.h"

#include <linux/neighbour.h>

#include <utility>

#include <base/logging.h>
#include <base/stl_util.h>

namespace portier {

using std::string;
using std::vector;

using base::TimeDelta;
using base::TimeTicks;
using shill::IPAddress;

using KeyPair = std::pair<const IPAddress, const string>;
using NeighPair = std::pair<KeyPair, NeighborCacheEntry>;

namespace {

// Amount of time  between an entry being inserted and it being removed
// as obsolete.
constexpr TimeDelta kEntryExpiryTimeout = TimeDelta::FromSeconds(30);

// Checks if the specified |nud_state| is one of the valid NUD states
// recognized by the Linux kernel.  These states are specified in
// <linux/neighbour.h>.  Note that dummy states are not recognized
// as valid.
bool IsValidNudState(uint8_t nud_state) {
  switch (nud_state) {
    case NUD_REACHABLE:
    case NUD_PROBE:
    case NUD_DELAY:
    case NUD_STALE:
    case NUD_INCOMPLETE:
    case NUD_FAILED:
      return true;
  }
  return false;
}

// Converts a NUD state into a relative score used for ranking the
// entries.  The higher the score, the high priority that NUD state
// has when multiple entries can be used.  This score is based on the
// order of preferred states in RFC 4389 Section 4.1.
int GetNudScore(uint8_t nud_state) {
  switch (nud_state) {
    case NUD_REACHABLE:
      return 5;
    case NUD_PROBE:
      return 4;
    case NUD_DELAY:
      return 3;
    case NUD_STALE:
      return 2;
    case NUD_INCOMPLETE:
      return 1;
    case NUD_FAILED:
      return 0;
  }
  return -1;
}

}  // namespace

NeighborCacheEntry::NeighborCacheEntry()
    : is_router(false), nud_state(NUD_NONE) {}

bool NeighborCache::GetEntry(const IPAddress& ip_address,
                             const string& pg_name,
                             NeighborCacheEntry* entry_out) const {
  DCHECK(entry_out);
  auto it = entries_.find(KeyPair(ip_address, pg_name));
  if (it != entries_.end()) {
    *entry_out = it->second;
    return true;
  }
  return false;
}

bool NeighborCache::GetInterfaceRouter(const std::string& if_name,
                                       const std::string& pg_name,
                                       NeighborCacheEntry* entry_out) const {
  DCHECK(entry_out);
  // Using an initial score of 0 to prevent routers in a FAILED states from
  // being returned.
  int nud_score = 0;
  for (const auto& pair : entries_) {
    // Check if potential match, skip if not.
    if (!pair.second.is_router || pair.second.if_name != if_name ||
        pair.first.second != pg_name) {
      continue;
    }
    int new_nud_score = GetNudScore(pair.second.nud_state);
    if (new_nud_score > nud_score) {
      nud_score = new_nud_score;
      *entry_out = pair.second;
    }
  }
  return nud_score > 0;
}

bool NeighborCache::HasEntry(const IPAddress& ip_address,
                             const string& pg_name) const {
  const KeyPair key(ip_address, pg_name);
  return base::ContainsKey(entries_, key);
}

bool NeighborCache::InsertEntry(const string& pg_name,
                                const NeighborCacheEntry& entry,
                                TimeTicks now) {
  // Validating based on needs of IPv6 ND Proxying.
  if (!entry.ip_address.IsValid() ||
      entry.ip_address.family() != IPAddress::kFamilyIPv6 ||
      !entry.ll_address.IsValid() || entry.if_name.size() == 0 ||
      pg_name.size() == 0 || !IsValidNudState(entry.nud_state)) {
    return false;
  }
  const KeyPair key(entry.ip_address, pg_name);
  NeighborCacheEntry& new_entry = entries_[key];
  new_entry = entry;
  entries_[key].expiry_time = now + kEntryExpiryTimeout;
  return true;
}

void NeighborCache::RemoveEntry(const IPAddress& ip_address,
                                const string& pg_name) {
  entries_.erase(KeyPair(ip_address, pg_name));
}

void NeighborCache::ClearForInterface(const string& if_name) {
  for (auto it = entries_.begin(); it != entries_.end();) {
    if (it->second.if_name == if_name) {
      it = entries_.erase(it);
    } else {
      ++it;
    }
  }
}

void NeighborCache::ClearForGroup(const string& pg_name) {
  for (auto it = entries_.begin(); it != entries_.end();) {
    if (it->first.second == pg_name) {
      it = entries_.erase(it);
    } else {
      ++it;
    }
  }
}

void NeighborCache::Clear() {
  entries_.clear();
}

void NeighborCache::ClearExpired(TimeTicks now) {
  for (auto it = entries_.begin(); it != entries_.end();) {
    if (it->second.expiry_time <= now) {
      it = entries_.erase(it);
    } else {
      ++it;
    }
  }
}

}  // namespace portier
