// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements.  See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership.  The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License.  You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include <stdint.h>

#include <netinet/in.h>

#include <netlink/addr.h>
#include <netlink/cache.h>
#include <netlink/errno.h>
#include <netlink/netlink.h>
#include <netlink/object.h>
#include <netlink/socket.h>

#include <netlink/route/route.h>

#include <glog/logging.h>

#include <stout/error.hpp>
#include <stout/foreach.hpp>
#include <stout/none.hpp>
#include <stout/stringify.hpp>

#include "linux/routing/internal.hpp"
#include "linux/routing/route.hpp"

#include "linux/routing/link/link.hpp"

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

namespace routing {
namespace route {

Try<vector<Rule>> table()
{
  Try<Netlink<struct nl_sock>> socket = routing::socket();
  if (socket.isError()) {
    return Error(socket.error());
  }

  // Dump all the routes (for IPv4) from kernel.
  struct nl_cache* c = nullptr;
  int error = rtnl_route_alloc_cache(socket->get(), AF_INET, 0, &c);
  if (error != 0) {
    return Error(nl_geterror(error));
  }

  Netlink<struct nl_cache> cache(c);

  vector<Rule> results;

  // Scan the routes and look for entries in the main routing table.
  for (struct nl_object* o = nl_cache_get_first(cache.get());
       o != nullptr; o = nl_cache_get_next(o)) {
    struct rtnl_route* route = (struct rtnl_route*) o;

    // TODO(jieyu): Currently, we assume each route in the routing
    // table has only one hop (which is true in most environments).
    if (rtnl_route_get_table(route) == RT_TABLE_MAIN &&
        rtnl_route_get_nnexthops(route) == 1) {
      CHECK_EQ(AF_INET, rtnl_route_get_family(route));

      // Get the destination IP network if exists.
      Option<net::IP::Network> destination;
      struct nl_addr* dst = rtnl_route_get_dst(route);
      if (dst != nullptr && !nl_addr_iszero(dst)) {
        struct in_addr* addr = (struct in_addr*) nl_addr_get_binary_addr(dst);
        Try<net::IP::Network> network = net::IP::Network::create(
            net::IP(*addr),
            nl_addr_get_prefixlen(dst));

        if (network.isError()) {
          return Error(
              "Invalid IP network format from the routing table: " +
              network.error());
        }

        destination = network.get();
      }

      // Get the default gateway if exists.
      Option<net::IP> gateway;
      struct rtnl_nexthop* hop = rtnl_route_nexthop_n(route, 0);
      struct nl_addr* gw = rtnl_route_nh_get_gateway(CHECK_NOTNULL(hop));
      if (gw != nullptr && !nl_addr_iszero(gw)) {
        struct in_addr* addr = (struct in_addr*) nl_addr_get_binary_addr(gw);
        gateway = net::IP(*addr);
      }

      // Get the destination link.
      int index = rtnl_route_nh_get_ifindex(hop);
      Result<string> link = link::name(index);
      if (link.isError()) {
        return Error("Failed to get the link name: " + link.error());
      } else if (link.isNone()) {
        return Error("Link of index " + stringify(index) + " is not found");
      }

      results.push_back(Rule(destination, gateway, link.get()));
    }
  }

  return results;
}


Result<net::IP> defaultGateway()
{
  Try<vector<Rule>> rules = table();
  if (rules.isError()) {
    return Error("Failed to get the routing table: " + rules.error());
  }

  foreach (const Rule& rule, rules.get()) {
    if (rule.destination.isNone() && rule.gateway.isSome()) {
      return rule.gateway.get();
    }
  }

  return None();
}

} // namespace route {
} // namespace routing {
