routing_table.cc revision 536820ddd33f63e1d95e6e04e1757bd0248bbe38
12c15d2c7ae814d95673ea48ec8f4eb582ef3652emukesh agrawal// Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
275e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart// Use of this source code is governed by a BSD-style license that can be
375e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart// found in the LICENSE file.
475e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart
575e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart#include "shill/routing_table.h"
675e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart
775e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart#include <arpa/inet.h>
875e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart#include <fcntl.h>
975e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart#include <linux/netlink.h>
1075e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart#include <linux/rtnetlink.h>
1175e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart#include <netinet/ether.h>
1275e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart#include <net/if.h>
1375e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart#include <net/if_arp.h>
1475e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart#include <string.h>
1575e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart#include <sys/socket.h>
1675e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart#include <time.h>
1775e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart#include <unistd.h>
1875e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart
1975e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart#include <string>
2075e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart
213e20a2341d0aeb7681e4ee0f89eae6817ade2b3bEric Shienbrood#include <base/bind.h>
2275e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart#include <base/file_path.h>
2375e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart#include <base/file_util.h>
2475e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart#include <base/hash_tables.h>
2575e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart#include <base/logging.h>
2675e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart#include <base/memory/scoped_ptr.h>
273e20a2341d0aeb7681e4ee0f89eae6817ade2b3bEric Shienbrood#include <base/stl_util.h>
2875e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart#include <base/stringprintf.h>
2975e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart
3075e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart#include "shill/byte_string.h"
3175e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart#include "shill/routing_table_entry.h"
3275e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart#include "shill/rtnl_handler.h"
3375e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart#include "shill/rtnl_listener.h"
3475e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart#include "shill/rtnl_message.h"
3575e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart
363e20a2341d0aeb7681e4ee0f89eae6817ade2b3bEric Shienbroodusing base::Bind;
373e20a2341d0aeb7681e4ee0f89eae6817ade2b3bEric Shienbroodusing base::Unretained;
3875e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewartusing std::string;
3975e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewartusing std::vector;
4075e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart
4175e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewartnamespace shill {
4275e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart
433e20a2341d0aeb7681e4ee0f89eae6817ade2b3bEric Shienbrood// TODO(ers): not using LAZY_INSTANCE_INITIALIZER
443e20a2341d0aeb7681e4ee0f89eae6817ade2b3bEric Shienbrood// because of http://crbug.com/114828
453e20a2341d0aeb7681e4ee0f89eae6817ade2b3bEric Shienbroodstatic base::LazyInstance<RoutingTable> g_routing_table = {0, {{0}}};
460d2ada3971075e78fb9900d0753c9ad94c15add4Paul Stewart
4775e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart// static
4875e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewartconst char RoutingTable::kRouteFlushPath4[] = "/proc/sys/net/ipv4/route/flush";
490d2ada3971075e78fb9900d0753c9ad94c15add4Paul Stewart// static
5075e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewartconst char RoutingTable::kRouteFlushPath6[] = "/proc/sys/net/ipv6/route/flush";
5175e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart
5275e89d2d5ecb3c42a869f485d4483fd2176381c0Paul StewartRoutingTable::RoutingTable()
533e20a2341d0aeb7681e4ee0f89eae6817ade2b3bEric Shienbrood    : route_callback_(Bind(&RoutingTable::RouteMsgHandler, Unretained(this))),
54f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart      route_listener_(NULL),
55f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart      rtnl_handler_(RTNLHandler::GetInstance()) {
5675e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart  VLOG(2) << __func__;
5775e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart}
5875e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart
5975e89d2d5ecb3c42a869f485d4483fd2176381c0Paul StewartRoutingTable::~RoutingTable() {}
6075e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart
6175e89d2d5ecb3c42a869f485d4483fd2176381c0Paul StewartRoutingTable* RoutingTable::GetInstance() {
620d2ada3971075e78fb9900d0753c9ad94c15add4Paul Stewart  return g_routing_table.Pointer();
6375e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart}
6475e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart
6575e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewartvoid RoutingTable::Start() {
6675e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart  VLOG(2) << __func__;
6775e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart
6875e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart  route_listener_.reset(
693e20a2341d0aeb7681e4ee0f89eae6817ade2b3bEric Shienbrood      new RTNLListener(RTNLHandler::kRequestRoute, route_callback_));
70f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart  rtnl_handler_->RequestDump(RTNLHandler::kRequestRoute);
7175e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart}
7275e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart
7375e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewartvoid RoutingTable::Stop() {
7475e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart  VLOG(2) << __func__;
7575e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart
7675e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart  route_listener_.reset();
7775e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart}
7875e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart
7975e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewartbool RoutingTable::AddRoute(int interface_index,
8075e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart                            const RoutingTableEntry &entry) {
81f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart  VLOG(2) << __func__ << ": "
82f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart          << "destination " << entry.dst.ToString()
83f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart          << " index " << interface_index
84f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart          << " gateway " << entry.gateway.ToString()
85f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart          << " metric " << entry.metric;
8675e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart
8775e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart  CHECK(!entry.from_rtnl);
8875e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart  if (!ApplyRoute(interface_index,
8975e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart                  entry,
909a908080fc2a72dbf06f995b878fc8a3693b725aPaul Stewart                  RTNLMessage::kModeAdd,
9175e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart                  NLM_F_CREATE | NLM_F_EXCL)) {
9275e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart    return false;
9375e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart  }
9475e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart  tables_[interface_index].push_back(entry);
9575e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart  return true;
9675e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart}
9775e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart
9875e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewartbool RoutingTable::GetDefaultRoute(int interface_index,
9975e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart                                   IPAddress::Family family,
10075e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart                                   RoutingTableEntry *entry) {
101d4ef677ad36ef34f59529af557adbe77b2c29c80mukesh agrawal  RoutingTableEntry *found_entry;
102d4ef677ad36ef34f59529af557adbe77b2c29c80mukesh agrawal  bool ret = GetDefaultRouteInternal(interface_index, family, &found_entry);
103d4ef677ad36ef34f59529af557adbe77b2c29c80mukesh agrawal  if (ret) {
104d4ef677ad36ef34f59529af557adbe77b2c29c80mukesh agrawal    *entry = *found_entry;
105d4ef677ad36ef34f59529af557adbe77b2c29c80mukesh agrawal  }
106d4ef677ad36ef34f59529af557adbe77b2c29c80mukesh agrawal  return ret;
107d4ef677ad36ef34f59529af557adbe77b2c29c80mukesh agrawal}
108d4ef677ad36ef34f59529af557adbe77b2c29c80mukesh agrawal
109d4ef677ad36ef34f59529af557adbe77b2c29c80mukesh agrawalbool RoutingTable::GetDefaultRouteInternal(int interface_index,
110d4ef677ad36ef34f59529af557adbe77b2c29c80mukesh agrawal                                           IPAddress::Family family,
111d4ef677ad36ef34f59529af557adbe77b2c29c80mukesh agrawal                                           RoutingTableEntry **entry) {
112f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart  VLOG(2) << __func__ << " index " << interface_index
113f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart          << " family " << IPAddress::GetAddressFamilyName(family);
11475e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart
11575e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart  base::hash_map<int, vector<RoutingTableEntry> >::iterator table =
11675e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart    tables_.find(interface_index);
11775e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart
11875e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart  if (table == tables_.end()) {
1192c15d2c7ae814d95673ea48ec8f4eb582ef3652emukesh agrawal    VLOG(2) << __func__ << " no table";
12075e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart    return false;
12175e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart  }
12275e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart
12375e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart  vector<RoutingTableEntry>::iterator nent;
12475e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart
12575e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart  for (nent = table->second.begin(); nent != table->second.end(); ++nent) {
12675e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart    if (nent->dst.IsDefault() && nent->dst.family() == family) {
127d4ef677ad36ef34f59529af557adbe77b2c29c80mukesh agrawal      *entry = &(*nent);
128f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart      VLOG(2) << __func__ << ": found"
129f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart              << " gateway " << nent->gateway.ToString()
130f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart              << " metric " << nent->metric;
13175e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart      return true;
13275e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart    }
13375e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart  }
13475e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart
1352c15d2c7ae814d95673ea48ec8f4eb582ef3652emukesh agrawal  VLOG(2) << __func__ << " no route";
13675e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart  return false;
13775e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart}
13875e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart
13975e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewartbool RoutingTable::SetDefaultRoute(int interface_index,
14075e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart                                   const IPConfigRefPtr &ipconfig,
14175e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart                                   uint32 metric) {
1422c15d2c7ae814d95673ea48ec8f4eb582ef3652emukesh agrawal  VLOG(2) << __func__ << " index " << interface_index << " metric " << metric;
1432c15d2c7ae814d95673ea48ec8f4eb582ef3652emukesh agrawal
14475e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart  const IPConfig::Properties &ipconfig_props = ipconfig->properties();
145d4ef677ad36ef34f59529af557adbe77b2c29c80mukesh agrawal  RoutingTableEntry *old_entry;
14675e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart  IPAddress gateway_address(ipconfig_props.address_family);
14775e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart  if (!gateway_address.SetAddressFromString(ipconfig_props.gateway)) {
14875e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart    return false;
14975e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart  }
15075e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart
151d4ef677ad36ef34f59529af557adbe77b2c29c80mukesh agrawal  if (GetDefaultRouteInternal(interface_index,
152d4ef677ad36ef34f59529af557adbe77b2c29c80mukesh agrawal                              ipconfig_props.address_family,
153d4ef677ad36ef34f59529af557adbe77b2c29c80mukesh agrawal                              &old_entry)) {
154d4ef677ad36ef34f59529af557adbe77b2c29c80mukesh agrawal    if (old_entry->gateway.Equals(gateway_address)) {
155d4ef677ad36ef34f59529af557adbe77b2c29c80mukesh agrawal      if (old_entry->metric != metric) {
156c1dec4d5cad7c6ee2cd8dbc4f47e4d30403dcca1Paul Stewart        ReplaceMetric(interface_index, old_entry, metric);
15775e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart      }
15875e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart      return true;
15975e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart    } else {
160d4ef677ad36ef34f59529af557adbe77b2c29c80mukesh agrawal      // TODO(quiche): Update internal state as well?
16175e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart      ApplyRoute(interface_index,
162d4ef677ad36ef34f59529af557adbe77b2c29c80mukesh agrawal                 *old_entry,
1639a908080fc2a72dbf06f995b878fc8a3693b725aPaul Stewart                 RTNLMessage::kModeDelete,
16475e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart                 0);
16575e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart    }
16675e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart  }
16775e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart
16875e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart  IPAddress default_address(ipconfig_props.address_family);
16975e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart  default_address.SetAddressToDefault();
17075e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart
17175e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart  return AddRoute(interface_index,
17275e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart                  RoutingTableEntry(default_address,
17375e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart                                    default_address,
17475e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart                                    gateway_address,
17575e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart                                    metric,
17675e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart                                    RT_SCOPE_UNIVERSE,
17775e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart                                    false));
17875e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart}
17975e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart
1803f68bb1e3768969a1db686325ae9a84c8fd06005Paul Stewartbool RoutingTable::ConfigureRoutes(int interface_index,
1813f68bb1e3768969a1db686325ae9a84c8fd06005Paul Stewart                                   const IPConfigRefPtr &ipconfig,
1823f68bb1e3768969a1db686325ae9a84c8fd06005Paul Stewart                                   uint32 metric) {
1833f68bb1e3768969a1db686325ae9a84c8fd06005Paul Stewart  bool ret = true;
1843f68bb1e3768969a1db686325ae9a84c8fd06005Paul Stewart
1853f68bb1e3768969a1db686325ae9a84c8fd06005Paul Stewart  IPAddress::Family address_family = ipconfig->properties().address_family;
1863f68bb1e3768969a1db686325ae9a84c8fd06005Paul Stewart  const vector<IPConfig::Route> &routes = ipconfig->properties().routes;
1873f68bb1e3768969a1db686325ae9a84c8fd06005Paul Stewart
1883f68bb1e3768969a1db686325ae9a84c8fd06005Paul Stewart  for (vector<IPConfig::Route>::const_iterator it = routes.begin();
1893f68bb1e3768969a1db686325ae9a84c8fd06005Paul Stewart       it != routes.end();
1903f68bb1e3768969a1db686325ae9a84c8fd06005Paul Stewart       ++it) {
1913f68bb1e3768969a1db686325ae9a84c8fd06005Paul Stewart    VLOG(3) << "Installing route:"
1923f68bb1e3768969a1db686325ae9a84c8fd06005Paul Stewart            << " Destination: " << it->host
1933f68bb1e3768969a1db686325ae9a84c8fd06005Paul Stewart            << " Netmask: " << it->netmask
1943f68bb1e3768969a1db686325ae9a84c8fd06005Paul Stewart            << " Gateway: " << it->gateway;
1953f68bb1e3768969a1db686325ae9a84c8fd06005Paul Stewart    IPAddress destination_address(address_family);
1963f68bb1e3768969a1db686325ae9a84c8fd06005Paul Stewart    IPAddress source_address(address_family);  // Left as default.
1973f68bb1e3768969a1db686325ae9a84c8fd06005Paul Stewart    IPAddress gateway_address(address_family);
1983f68bb1e3768969a1db686325ae9a84c8fd06005Paul Stewart    if (!destination_address.SetAddressFromString(it->host)) {
1993f68bb1e3768969a1db686325ae9a84c8fd06005Paul Stewart      LOG(ERROR) << "Failed to parse host "
2003f68bb1e3768969a1db686325ae9a84c8fd06005Paul Stewart                 << it->host;
2013f68bb1e3768969a1db686325ae9a84c8fd06005Paul Stewart      ret = false;
2023f68bb1e3768969a1db686325ae9a84c8fd06005Paul Stewart      continue;
2033f68bb1e3768969a1db686325ae9a84c8fd06005Paul Stewart    }
2043f68bb1e3768969a1db686325ae9a84c8fd06005Paul Stewart    if (!gateway_address.SetAddressFromString(it->gateway)) {
2053f68bb1e3768969a1db686325ae9a84c8fd06005Paul Stewart      LOG(ERROR) << "Failed to parse gateway "
2063f68bb1e3768969a1db686325ae9a84c8fd06005Paul Stewart                 << it->gateway;
2073f68bb1e3768969a1db686325ae9a84c8fd06005Paul Stewart      ret = false;
2083f68bb1e3768969a1db686325ae9a84c8fd06005Paul Stewart      continue;
2093f68bb1e3768969a1db686325ae9a84c8fd06005Paul Stewart    }
2103f68bb1e3768969a1db686325ae9a84c8fd06005Paul Stewart    destination_address.set_prefix(
2113f68bb1e3768969a1db686325ae9a84c8fd06005Paul Stewart        IPAddress::GetPrefixLengthFromMask(address_family, it->netmask));
2123f68bb1e3768969a1db686325ae9a84c8fd06005Paul Stewart    if (!AddRoute(interface_index,
2133f68bb1e3768969a1db686325ae9a84c8fd06005Paul Stewart                  RoutingTableEntry(destination_address,
2143f68bb1e3768969a1db686325ae9a84c8fd06005Paul Stewart                                    source_address,
2153f68bb1e3768969a1db686325ae9a84c8fd06005Paul Stewart                                    gateway_address,
2163f68bb1e3768969a1db686325ae9a84c8fd06005Paul Stewart                                    metric,
2173f68bb1e3768969a1db686325ae9a84c8fd06005Paul Stewart                                    RT_SCOPE_UNIVERSE,
2183f68bb1e3768969a1db686325ae9a84c8fd06005Paul Stewart                                    false))) {
2193f68bb1e3768969a1db686325ae9a84c8fd06005Paul Stewart      ret = false;
2203f68bb1e3768969a1db686325ae9a84c8fd06005Paul Stewart    }
2213f68bb1e3768969a1db686325ae9a84c8fd06005Paul Stewart  }
2223f68bb1e3768969a1db686325ae9a84c8fd06005Paul Stewart  return ret;
2233f68bb1e3768969a1db686325ae9a84c8fd06005Paul Stewart}
2243f68bb1e3768969a1db686325ae9a84c8fd06005Paul Stewart
225fb46caf4f23a41e73dfd87547121b5fb0230295aThieu Levoid RoutingTable::FlushRoutes(int interface_index) {
22675e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart  VLOG(2) << __func__;
22775e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart
22875e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart  base::hash_map<int, vector<RoutingTableEntry> >::iterator table =
22975e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart    tables_.find(interface_index);
23075e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart
23175e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart  if (table == tables_.end()) {
23275e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart    return;
23375e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart  }
23475e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart
23575e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart  vector<RoutingTableEntry>::iterator nent;
23675e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart
23775e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart  for (nent = table->second.begin(); nent != table->second.end(); ++nent) {
238caef8936381e9ae1fd765866e4759d42bbb19ad9Thieu Le      ApplyRoute(interface_index, *nent, RTNLMessage::kModeDelete, 0);
23975e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart  }
240fb46caf4f23a41e73dfd87547121b5fb0230295aThieu Le  table->second.clear();
24175e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart}
24275e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart
24375e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewartvoid RoutingTable::ResetTable(int interface_index) {
24475e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart  tables_.erase(interface_index);
24575e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart}
24675e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart
24775e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewartvoid RoutingTable::SetDefaultMetric(int interface_index, uint32 metric) {
248f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart  VLOG(2) << __func__ << " index " << interface_index << " metric " << metric;
24975e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart
250d4ef677ad36ef34f59529af557adbe77b2c29c80mukesh agrawal  RoutingTableEntry *entry;
251d4ef677ad36ef34f59529af557adbe77b2c29c80mukesh agrawal  if (GetDefaultRouteInternal(
252d4ef677ad36ef34f59529af557adbe77b2c29c80mukesh agrawal          interface_index, IPAddress::kFamilyIPv4, &entry) &&
253d4ef677ad36ef34f59529af557adbe77b2c29c80mukesh agrawal      entry->metric != metric) {
254c1dec4d5cad7c6ee2cd8dbc4f47e4d30403dcca1Paul Stewart    ReplaceMetric(interface_index, entry, metric);
25575e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart  }
25675e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart
257d4ef677ad36ef34f59529af557adbe77b2c29c80mukesh agrawal  if (GetDefaultRouteInternal(
258d4ef677ad36ef34f59529af557adbe77b2c29c80mukesh agrawal          interface_index, IPAddress::kFamilyIPv6, &entry) &&
259d4ef677ad36ef34f59529af557adbe77b2c29c80mukesh agrawal      entry->metric != metric) {
260c1dec4d5cad7c6ee2cd8dbc4f47e4d30403dcca1Paul Stewart    ReplaceMetric(interface_index, entry, metric);
26175e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart  }
26275e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart}
26375e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart
264f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart// static
265f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewartbool RoutingTable::ParseRoutingTableMessage(const RTNLMessage &message,
266f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart                                            int *interface_index,
267f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart                                            RoutingTableEntry *entry) {
268f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart  if (message.type() != RTNLMessage::kTypeRoute ||
269f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart      message.family() == IPAddress::kFamilyUnknown ||
270f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart      !message.HasAttribute(RTA_OIF)) {
271f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart    return false;
27275e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart  }
27375e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart
274f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart  const RTNLMessage::RouteStatus &route_status = message.route_status();
27575e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart
27675e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart  if (route_status.type != RTN_UNICAST ||
27775e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart      route_status.table != RT_TABLE_MAIN) {
278f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart    return false;
27975e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart  }
28075e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart
281f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart  uint32 interface_index_u32 = 0;
282f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart  if (!message.GetAttribute(RTA_OIF).ConvertToCPUUInt32(&interface_index_u32)) {
283f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart    return false;
28475e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart  }
285f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart  *interface_index = interface_index_u32;
28675e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart
28775e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart  uint32 metric = 0;
288f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart  if (message.HasAttribute(RTA_PRIORITY)) {
289f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart    message.GetAttribute(RTA_PRIORITY).ConvertToCPUUInt32(&metric);
29075e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart  }
29175e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart
292f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart  IPAddress default_addr(message.family());
29375e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart  default_addr.SetAddressToDefault();
29475e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart
29575e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart  ByteString dst_bytes(default_addr.address());
296f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart  if (message.HasAttribute(RTA_DST)) {
297f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart    dst_bytes = message.GetAttribute(RTA_DST);
29875e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart  }
29975e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart  ByteString src_bytes(default_addr.address());
300f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart  if (message.HasAttribute(RTA_SRC)) {
301f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart    src_bytes = message.GetAttribute(RTA_SRC);
30275e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart  }
30375e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart  ByteString gateway_bytes(default_addr.address());
304f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart  if (message.HasAttribute(RTA_GATEWAY)) {
305f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart    gateway_bytes = message.GetAttribute(RTA_GATEWAY);
306f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart  }
307f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart
308f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart  entry->dst = IPAddress(message.family(), dst_bytes, route_status.dst_prefix);
309f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart  entry->src = IPAddress(message.family(), src_bytes, route_status.src_prefix);
310f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart  entry->gateway = IPAddress(message.family(), gateway_bytes);
311f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart  entry->metric = metric;
312f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart  entry->scope = route_status.scope;
313f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart  entry->from_rtnl = true;
314f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart
315f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart  return true;
316f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart}
317f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart
318f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewartvoid RoutingTable::RouteMsgHandler(const RTNLMessage &message) {
319f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart  int interface_index;
320f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart  RoutingTableEntry entry;
321f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart
322f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart  if (!ParseRoutingTableMessage(message, &interface_index, &entry)) {
323f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart    return;
32475e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart  }
32575e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart
326f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart  if (!route_query_sequences_.empty() &&
327f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart      message.route_status().protocol == RTPROT_UNSPEC) {
328f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart    VLOG(3) << __func__ << ": Message seq: " << message.seq()
329f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart            << " mode " << message.mode()
330f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart            << ", next query seq: " << route_query_sequences_.front();
331f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart
332f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart    // Purge queries that have expired (sequence number of this message is
333f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart    // greater than that of the head of the route query sequence).  Do the
334f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart    // math in a way that's roll-over independent.
335f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart    while (route_query_sequences_.front() - message.seq() > kuint32max / 2) {
336f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart      LOG(ERROR) << __func__ << ": Purging un-replied route request sequence "
337f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart                 << route_query_sequences_.front()
338f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart                 << " (< " << message.seq() << ")";
339f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart      route_query_sequences_.pop();
340f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart      if (route_query_sequences_.empty())
341f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart        return;
342f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart    }
343f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart
344f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart    if (route_query_sequences_.front() == message.seq()) {
345f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart      VLOG(2) << __func__ << ": Adding host route to " << entry.dst.ToString();
346f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart      route_query_sequences_.pop();
347f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart      RoutingTableEntry add_entry(entry);
348f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart      add_entry.from_rtnl = false;
349f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart      AddRoute(interface_index, add_entry);
350f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart    }
351f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart    return;
352f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart  } else if (message.route_status().protocol != RTPROT_BOOT) {
353f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart    // Responses to route queries come back with a protocol of
354f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart    // RTPROT_UNSPEC.  Otherwise, normal route updates that we are
355f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart    // interested in come with a protocol of RTPROT_BOOT.
356f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart    return;
357f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart  }
35875e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart
35975e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart  vector<RoutingTableEntry> &table = tables_[interface_index];
36075e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart  vector<RoutingTableEntry>::iterator nent;
36175e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart  for (nent = table.begin(); nent != table.end(); ++nent) {
36275e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart    if (nent->dst.Equals(entry.dst) &&
36375e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart        nent->src.Equals(entry.src) &&
36475e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart        nent->gateway.Equals(entry.gateway) &&
36575e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart        nent->scope == entry.scope) {
366f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart      if (message.mode() == RTNLMessage::kModeDelete &&
367c1dec4d5cad7c6ee2cd8dbc4f47e4d30403dcca1Paul Stewart          nent->metric == entry.metric) {
36875e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart        table.erase(nent);
369f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart      } else if (message.mode() == RTNLMessage::kModeAdd) {
37075e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart        nent->from_rtnl = true;
37175e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart        nent->metric = entry.metric;
37275e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart      }
37375e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart      return;
37475e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart    }
37575e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart  }
37675e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart
377f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart  if (message.mode() == RTNLMessage::kModeAdd) {
378f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart    VLOG(2) << __func__ << " adding"
379f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart            << " destination " << entry.dst.ToString()
380f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart            << " index " << interface_index
381f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart            << " gateway " << entry.gateway.ToString()
382f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart            << " metric " << entry.metric;
38375e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart    table.push_back(entry);
38475e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart  }
38575e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart}
38675e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart
38775e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewartbool RoutingTable::ApplyRoute(uint32 interface_index,
38875e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart                              const RoutingTableEntry &entry,
3899a908080fc2a72dbf06f995b878fc8a3693b725aPaul Stewart                              RTNLMessage::Mode mode,
39075e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart                              unsigned int flags) {
3913f68bb1e3768969a1db686325ae9a84c8fd06005Paul Stewart  VLOG(2) << base::StringPrintf("%s: dst %s/%d src %s/%d index %d mode %d "
3923f68bb1e3768969a1db686325ae9a84c8fd06005Paul Stewart                                "flags 0x%x",
393bf14e94cbd47d6320eec846f1ca4def026840e14mukesh agrawal                                __func__, entry.dst.ToString().c_str(),
3943f68bb1e3768969a1db686325ae9a84c8fd06005Paul Stewart                                entry.dst.prefix(),
3953f68bb1e3768969a1db686325ae9a84c8fd06005Paul Stewart                                entry.src.ToString().c_str(),
3963f68bb1e3768969a1db686325ae9a84c8fd06005Paul Stewart                                entry.src.prefix(), interface_index, mode,
3973f68bb1e3768969a1db686325ae9a84c8fd06005Paul Stewart                                flags);
39875e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart
399f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart  RTNLMessage message(
4009a908080fc2a72dbf06f995b878fc8a3693b725aPaul Stewart      RTNLMessage::kTypeRoute,
40175e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart      mode,
402e613202d36e3bfb06a40eea1888694413210ef7ePaul Stewart      NLM_F_REQUEST | flags,
40375e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart      0,
40475e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart      0,
40575e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart      0,
40675e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart      entry.dst.family());
40775e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart
408f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart  message.set_route_status(RTNLMessage::RouteStatus(
4099e3fcd7141240bc5efd0bf1513b9e78aa79d90ebPaul Stewart      entry.dst.prefix(),
4109e3fcd7141240bc5efd0bf1513b9e78aa79d90ebPaul Stewart      entry.src.prefix(),
41175e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart      RT_TABLE_MAIN,
41275e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart      RTPROT_BOOT,
41375e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart      entry.scope,
41475e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart      RTN_UNICAST,
41575e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart      0));
41675e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart
417f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart  message.SetAttribute(RTA_DST, entry.dst.address());
41875e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart  if (!entry.src.IsDefault()) {
419f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart    message.SetAttribute(RTA_SRC, entry.src.address());
42075e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart  }
42175e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart  if (!entry.gateway.IsDefault()) {
422f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart    message.SetAttribute(RTA_GATEWAY, entry.gateway.address());
42375e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart  }
424f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart  message.SetAttribute(RTA_PRIORITY,
425f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart                       ByteString::CreateFromCPUUInt32(entry.metric));
426f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart  message.SetAttribute(RTA_OIF,
427f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart                       ByteString::CreateFromCPUUInt32(interface_index));
42875e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart
429f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart  return rtnl_handler_->SendMessage(&message);
43075e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart}
43175e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart
432c1dec4d5cad7c6ee2cd8dbc4f47e4d30403dcca1Paul Stewart// Somewhat surprisingly, the kernel allows you to create multiple routes
433c1dec4d5cad7c6ee2cd8dbc4f47e4d30403dcca1Paul Stewart// to the same destination through the same interface with different metrics.
434c1dec4d5cad7c6ee2cd8dbc4f47e4d30403dcca1Paul Stewart// Therefore, to change the metric on a route, we can't just use the
435c1dec4d5cad7c6ee2cd8dbc4f47e4d30403dcca1Paul Stewart// NLM_F_REPLACE flag by itself.  We have to explicitly remove the old route.
436c1dec4d5cad7c6ee2cd8dbc4f47e4d30403dcca1Paul Stewart// We do so after creating the route at a new metric so there is no traffic
437c1dec4d5cad7c6ee2cd8dbc4f47e4d30403dcca1Paul Stewart// disruption to existing network streams.
438c1dec4d5cad7c6ee2cd8dbc4f47e4d30403dcca1Paul Stewartvoid RoutingTable::ReplaceMetric(uint32 interface_index,
439d4ef677ad36ef34f59529af557adbe77b2c29c80mukesh agrawal                                 RoutingTableEntry *entry,
440c1dec4d5cad7c6ee2cd8dbc4f47e4d30403dcca1Paul Stewart                                 uint32 metric) {
441f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart  VLOG(2) << __func__ << " index " << interface_index << " metric " << metric;
442d4ef677ad36ef34f59529af557adbe77b2c29c80mukesh agrawal  RoutingTableEntry new_entry = *entry;
443c1dec4d5cad7c6ee2cd8dbc4f47e4d30403dcca1Paul Stewart  new_entry.metric = metric;
444c1dec4d5cad7c6ee2cd8dbc4f47e4d30403dcca1Paul Stewart  // First create the route at the new metric.
445c1dec4d5cad7c6ee2cd8dbc4f47e4d30403dcca1Paul Stewart  ApplyRoute(interface_index, new_entry, RTNLMessage::kModeAdd,
446c1dec4d5cad7c6ee2cd8dbc4f47e4d30403dcca1Paul Stewart             NLM_F_CREATE | NLM_F_REPLACE);
447c1dec4d5cad7c6ee2cd8dbc4f47e4d30403dcca1Paul Stewart  // Then delete the route at the old metric.
448d4ef677ad36ef34f59529af557adbe77b2c29c80mukesh agrawal  ApplyRoute(interface_index, *entry, RTNLMessage::kModeDelete, 0);
449d4ef677ad36ef34f59529af557adbe77b2c29c80mukesh agrawal  // Now, update our routing table (via |*entry|) from |new_entry|.
450d4ef677ad36ef34f59529af557adbe77b2c29c80mukesh agrawal  *entry = new_entry;
451c1dec4d5cad7c6ee2cd8dbc4f47e4d30403dcca1Paul Stewart}
452c1dec4d5cad7c6ee2cd8dbc4f47e4d30403dcca1Paul Stewart
45375e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewartbool RoutingTable::FlushCache() {
45475e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart  static const char *kPaths[2] = { kRouteFlushPath4, kRouteFlushPath6 };
45575e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart  bool ret = true;
45675e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart
45775e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart  VLOG(2) << __func__;
45875e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart
45975e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart  for (size_t i = 0; i < arraysize(kPaths); ++i) {
46075e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart    if (file_util::WriteFile(FilePath(kPaths[i]), "-1", 2) != 2) {
46175e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart      LOG(ERROR) << base::StringPrintf("Cannot write to route flush file %s",
46275e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart                                       kPaths[i]);
46375e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart      ret = false;
46475e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart    }
46575e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart  }
46675e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart
46775e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart  return ret;
46875e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart}
46975e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart
470f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewartbool RoutingTable::RequestRouteToHost(const IPAddress &address,
471f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart                                      int interface_index) {
472f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart  RTNLMessage message(
473f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart      RTNLMessage::kTypeRoute,
474f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart      RTNLMessage::kModeQuery,
475f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart      NLM_F_REQUEST,
476f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart      0,
477f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart      0,
478f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart      interface_index,
479f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart      address.family());
480f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart
481f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart  RTNLMessage::RouteStatus status;
482f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart  status.dst_prefix = address.prefix();
483f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart  message.set_route_status(status);
484f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart  message.SetAttribute(RTA_DST, address.address());
485536820ddd33f63e1d95e6e04e1757bd0248bbe38Paul Stewart
486536820ddd33f63e1d95e6e04e1757bd0248bbe38Paul Stewart  if (interface_index != -1) {
487536820ddd33f63e1d95e6e04e1757bd0248bbe38Paul Stewart    message.SetAttribute(RTA_OIF,
488536820ddd33f63e1d95e6e04e1757bd0248bbe38Paul Stewart                         ByteString::CreateFromCPUUInt32(interface_index));
489536820ddd33f63e1d95e6e04e1757bd0248bbe38Paul Stewart  }
490f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart
491f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart  if (!rtnl_handler_->SendMessage(&message)) {
492f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart    return false;
493f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart  }
494f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart
495f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart  // Save the sequence number of the request so we can create a route for
496f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart  // this host when we get a reply.
497f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart  route_query_sequences_.push(message.seq());
498f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart
499f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart  return true;
500f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart}
501f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart
50275e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart}  // namespace shill
503