1c0beca55d290fe0b1c96d78cbbcf94b05c23f5a5Peter Qiu//
2c0beca55d290fe0b1c96d78cbbcf94b05c23f5a5Peter Qiu// Copyright (C) 2012 The Android Open Source Project
3c0beca55d290fe0b1c96d78cbbcf94b05c23f5a5Peter Qiu//
4c0beca55d290fe0b1c96d78cbbcf94b05c23f5a5Peter Qiu// Licensed under the Apache License, Version 2.0 (the "License");
5c0beca55d290fe0b1c96d78cbbcf94b05c23f5a5Peter Qiu// you may not use this file except in compliance with the License.
6c0beca55d290fe0b1c96d78cbbcf94b05c23f5a5Peter Qiu// You may obtain a copy of the License at
7c0beca55d290fe0b1c96d78cbbcf94b05c23f5a5Peter Qiu//
8c0beca55d290fe0b1c96d78cbbcf94b05c23f5a5Peter Qiu//      http://www.apache.org/licenses/LICENSE-2.0
9c0beca55d290fe0b1c96d78cbbcf94b05c23f5a5Peter Qiu//
10c0beca55d290fe0b1c96d78cbbcf94b05c23f5a5Peter Qiu// Unless required by applicable law or agreed to in writing, software
11c0beca55d290fe0b1c96d78cbbcf94b05c23f5a5Peter Qiu// distributed under the License is distributed on an "AS IS" BASIS,
12c0beca55d290fe0b1c96d78cbbcf94b05c23f5a5Peter Qiu// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13c0beca55d290fe0b1c96d78cbbcf94b05c23f5a5Peter Qiu// See the License for the specific language governing permissions and
14c0beca55d290fe0b1c96d78cbbcf94b05c23f5a5Peter Qiu// limitations under the License.
15c0beca55d290fe0b1c96d78cbbcf94b05c23f5a5Peter Qiu//
1675e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart
1775e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart#include "shill/routing_table.h"
1875e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart
1975e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart#include <arpa/inet.h>
2075e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart#include <fcntl.h>
2175e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart#include <linux/netlink.h>
2275e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart#include <linux/rtnetlink.h>
2375e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart#include <netinet/ether.h>
24a41ab517725d036b63420f8445550246f8f50b99Alex Vakulenko#include <net/if.h>  // NOLINT - must be included after netinet/ether.h
2575e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart#include <net/if_arp.h>
2675e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart#include <string.h>
2775e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart#include <sys/socket.h>
2875e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart#include <time.h>
2975e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart#include <unistd.h>
3075e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart
31cd47732488cd101eaf0d3558dde5a7d4e4fc260bBen Chan#include <memory>
3275e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart#include <string>
3375e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart
343e20a2341d0aeb7681e4ee0f89eae6817ade2b3bEric Shienbrood#include <base/bind.h>
35a0ddf46e466bd4ba3d20952f0a6988c680c1af14Ben Chan#include <base/files/file_path.h>
3611c213f3cf64f27a0e42ee6da95e98bd1d4b3202Ben Chan#include <base/files/file_util.h>
373e20a2341d0aeb7681e4ee0f89eae6817ade2b3bEric Shienbrood#include <base/stl_util.h>
38a0ddf46e466bd4ba3d20952f0a6988c680c1af14Ben Chan#include <base/strings/stringprintf.h>
3975e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart
408d6b59704591ba9fad57751858835dc332dbdd37Peter Qiu#include "shill/ipconfig.h"
41b691efd71561246065eae3cdd73a96ca1b8a528dChristopher Wiley#include "shill/logging.h"
428d6b59704591ba9fad57751858835dc332dbdd37Peter Qiu#include "shill/net/byte_string.h"
438d6b59704591ba9fad57751858835dc332dbdd37Peter Qiu#include "shill/net/rtnl_handler.h"
448d6b59704591ba9fad57751858835dc332dbdd37Peter Qiu#include "shill/net/rtnl_listener.h"
458d6b59704591ba9fad57751858835dc332dbdd37Peter Qiu#include "shill/net/rtnl_message.h"
4675e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart#include "shill/routing_table_entry.h"
4775e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart
483e20a2341d0aeb7681e4ee0f89eae6817ade2b3bEric Shienbroodusing base::Bind;
490e1cdeae24dd678a5fe27c840802582c0ca45ec0Albert Chaulkusing base::FilePath;
503e20a2341d0aeb7681e4ee0f89eae6817ade2b3bEric Shienbroodusing base::Unretained;
51abf6d289b2d29487f0a51b6138a127707a38507aDarin Petkovusing std::deque;
5275e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewartusing std::string;
5375e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewartusing std::vector;
5475e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart
5575e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewartnamespace shill {
5675e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart
57c9c31d8497c3f053c2160408cc386010fc125fadRebecca Silbersteinnamespace Logging {
58c9c31d8497c3f053c2160408cc386010fc125fadRebecca Silbersteinstatic auto kModuleLogScope = ScopeLogger::kRoute;
591a212a6b98b22ad1d69652bb26a9e94138635476Paul Stewartstatic string ObjectID(RoutingTable* r) { return "(routing_table)"; }
60c9c31d8497c3f053c2160408cc386010fc125fadRebecca Silberstein}
61c9c31d8497c3f053c2160408cc386010fc125fadRebecca Silberstein
62bbdef5fc35b48d9b43ba0dc005384abd36b72213Ben Channamespace {
63bbdef5fc35b48d9b43ba0dc005384abd36b72213Ben Chanbase::LazyInstance<RoutingTable> g_routing_table = LAZY_INSTANCE_INITIALIZER;
64bbdef5fc35b48d9b43ba0dc005384abd36b72213Ben Chan}  // namespace
650d2ada3971075e78fb9900d0753c9ad94c15add4Paul Stewart
6675e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart// static
6775e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewartconst char RoutingTable::kRouteFlushPath4[] = "/proc/sys/net/ipv4/route/flush";
680d2ada3971075e78fb9900d0753c9ad94c15add4Paul Stewart// static
6975e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewartconst char RoutingTable::kRouteFlushPath6[] = "/proc/sys/net/ipv6/route/flush";
7075e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart
7175e89d2d5ecb3c42a869f485d4483fd2176381c0Paul StewartRoutingTable::RoutingTable()
723e20a2341d0aeb7681e4ee0f89eae6817ade2b3bEric Shienbrood    : route_callback_(Bind(&RoutingTable::RouteMsgHandler, Unretained(this))),
73f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart      rtnl_handler_(RTNLHandler::GetInstance()) {
74c9c31d8497c3f053c2160408cc386010fc125fadRebecca Silberstein  SLOG(this, 2) << __func__;
7575e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart}
7675e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart
7775e89d2d5ecb3c42a869f485d4483fd2176381c0Paul StewartRoutingTable::~RoutingTable() {}
7875e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart
7975e89d2d5ecb3c42a869f485d4483fd2176381c0Paul StewartRoutingTable* RoutingTable::GetInstance() {
800d2ada3971075e78fb9900d0753c9ad94c15add4Paul Stewart  return g_routing_table.Pointer();
8175e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart}
8275e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart
8375e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewartvoid RoutingTable::Start() {
84c9c31d8497c3f053c2160408cc386010fc125fadRebecca Silberstein  SLOG(this, 2) << __func__;
8575e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart
8675e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart  route_listener_.reset(
873e20a2341d0aeb7681e4ee0f89eae6817ade2b3bEric Shienbrood      new RTNLListener(RTNLHandler::kRequestRoute, route_callback_));
88f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart  rtnl_handler_->RequestDump(RTNLHandler::kRequestRoute);
8975e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart}
9075e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart
9175e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewartvoid RoutingTable::Stop() {
92c9c31d8497c3f053c2160408cc386010fc125fadRebecca Silberstein  SLOG(this, 2) << __func__;
9375e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart
9475e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart  route_listener_.reset();
9575e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart}
9675e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart
9775e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewartbool RoutingTable::AddRoute(int interface_index,
981a212a6b98b22ad1d69652bb26a9e94138635476Paul Stewart                            const RoutingTableEntry& entry) {
99c9c31d8497c3f053c2160408cc386010fc125fadRebecca Silberstein  SLOG(this, 2) << __func__ << ": "
100c9c31d8497c3f053c2160408cc386010fc125fadRebecca Silberstein                << "destination " << entry.dst.ToString()
101c9c31d8497c3f053c2160408cc386010fc125fadRebecca Silberstein                << " index " << interface_index
102c9c31d8497c3f053c2160408cc386010fc125fadRebecca Silberstein                << " gateway " << entry.gateway.ToString()
103c9c31d8497c3f053c2160408cc386010fc125fadRebecca Silberstein                << " metric " << entry.metric;
10475e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart
10575e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart  CHECK(!entry.from_rtnl);
10675e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart  if (!ApplyRoute(interface_index,
10775e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart                  entry,
1089a908080fc2a72dbf06f995b878fc8a3693b725aPaul Stewart                  RTNLMessage::kModeAdd,
10975e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart                  NLM_F_CREATE | NLM_F_EXCL)) {
11075e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart    return false;
11175e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart  }
11275e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart  tables_[interface_index].push_back(entry);
11375e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart  return true;
11475e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart}
11575e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart
11675e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewartbool RoutingTable::GetDefaultRoute(int interface_index,
11775e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart                                   IPAddress::Family family,
1181a212a6b98b22ad1d69652bb26a9e94138635476Paul Stewart                                   RoutingTableEntry* entry) {
1191a212a6b98b22ad1d69652bb26a9e94138635476Paul Stewart  RoutingTableEntry* found_entry;
120d4ef677ad36ef34f59529af557adbe77b2c29c80mukesh agrawal  bool ret = GetDefaultRouteInternal(interface_index, family, &found_entry);
121d4ef677ad36ef34f59529af557adbe77b2c29c80mukesh agrawal  if (ret) {
122d4ef677ad36ef34f59529af557adbe77b2c29c80mukesh agrawal    *entry = *found_entry;
123d4ef677ad36ef34f59529af557adbe77b2c29c80mukesh agrawal  }
124d4ef677ad36ef34f59529af557adbe77b2c29c80mukesh agrawal  return ret;
125d4ef677ad36ef34f59529af557adbe77b2c29c80mukesh agrawal}
126d4ef677ad36ef34f59529af557adbe77b2c29c80mukesh agrawal
127d4ef677ad36ef34f59529af557adbe77b2c29c80mukesh agrawalbool RoutingTable::GetDefaultRouteInternal(int interface_index,
128d4ef677ad36ef34f59529af557adbe77b2c29c80mukesh agrawal                                           IPAddress::Family family,
1291a212a6b98b22ad1d69652bb26a9e94138635476Paul Stewart                                           RoutingTableEntry** entry) {
130c9c31d8497c3f053c2160408cc386010fc125fadRebecca Silberstein  SLOG(this, 2) << __func__ << " index " << interface_index
131c9c31d8497c3f053c2160408cc386010fc125fadRebecca Silberstein                << " family " << IPAddress::GetAddressFamilyName(family);
13275e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart
1336db7b24348e69639e19cd6c408388b10d6ee54fePaul Stewart  Tables::iterator table = tables_.find(interface_index);
13475e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart  if (table == tables_.end()) {
135c9c31d8497c3f053c2160408cc386010fc125fadRebecca Silberstein    SLOG(this, 2) << __func__ << " no table";
13675e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart    return false;
13775e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart  }
13875e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart
1391a212a6b98b22ad1d69652bb26a9e94138635476Paul Stewart  for (auto& nent : table->second) {
1406db7b24348e69639e19cd6c408388b10d6ee54fePaul Stewart    if (nent.dst.IsDefault() && nent.dst.family() == family) {
1416db7b24348e69639e19cd6c408388b10d6ee54fePaul Stewart      *entry = &nent;
142c9c31d8497c3f053c2160408cc386010fc125fadRebecca Silberstein      SLOG(this, 2) << __func__ << ": found"
143c9c31d8497c3f053c2160408cc386010fc125fadRebecca Silberstein                    << " gateway " << nent.gateway.ToString()
144c9c31d8497c3f053c2160408cc386010fc125fadRebecca Silberstein                    << " metric " << nent.metric;
14575e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart      return true;
14675e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart    }
14775e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart  }
14875e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart
149c9c31d8497c3f053c2160408cc386010fc125fadRebecca Silberstein  SLOG(this, 2) << __func__ << " no route";
15075e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart  return false;
15175e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart}
15275e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart
15375e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewartbool RoutingTable::SetDefaultRoute(int interface_index,
1541a212a6b98b22ad1d69652bb26a9e94138635476Paul Stewart                                   const IPAddress& gateway_address,
155762bfb8ab200a387fe732ec92423a5f0afe11bcfPrabhu Kaliamoorthi                                   uint32_t metric,
156762bfb8ab200a387fe732ec92423a5f0afe11bcfPrabhu Kaliamoorthi                                   uint8_t table_id) {
157c9c31d8497c3f053c2160408cc386010fc125fadRebecca Silberstein  SLOG(this, 2) << __func__ << " index " << interface_index
158c9c31d8497c3f053c2160408cc386010fc125fadRebecca Silberstein                << " metric " << metric;
1592c15d2c7ae814d95673ea48ec8f4eb582ef3652emukesh agrawal
1601a212a6b98b22ad1d69652bb26a9e94138635476Paul Stewart  RoutingTableEntry* old_entry;
16175e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart
162d4ef677ad36ef34f59529af557adbe77b2c29c80mukesh agrawal  if (GetDefaultRouteInternal(interface_index,
1635b7ba8c2e9e5ab5e67c68d0cde963141beb501d8Paul Stewart                              gateway_address.family(),
164d4ef677ad36ef34f59529af557adbe77b2c29c80mukesh agrawal                              &old_entry)) {
165d4ef677ad36ef34f59529af557adbe77b2c29c80mukesh agrawal    if (old_entry->gateway.Equals(gateway_address)) {
166d4ef677ad36ef34f59529af557adbe77b2c29c80mukesh agrawal      if (old_entry->metric != metric) {
167c1dec4d5cad7c6ee2cd8dbc4f47e4d30403dcca1Paul Stewart        ReplaceMetric(interface_index, old_entry, metric);
16875e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart      }
16975e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart      return true;
17075e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart    } else {
171d4ef677ad36ef34f59529af557adbe77b2c29c80mukesh agrawal      // TODO(quiche): Update internal state as well?
17275e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart      ApplyRoute(interface_index,
173d4ef677ad36ef34f59529af557adbe77b2c29c80mukesh agrawal                 *old_entry,
1749a908080fc2a72dbf06f995b878fc8a3693b725aPaul Stewart                 RTNLMessage::kModeDelete,
17575e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart                 0);
17675e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart    }
17775e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart  }
17875e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart
1795b7ba8c2e9e5ab5e67c68d0cde963141beb501d8Paul Stewart  IPAddress default_address(gateway_address.family());
18075e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart  default_address.SetAddressToDefault();
18175e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart
18275e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart  return AddRoute(interface_index,
18375e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart                  RoutingTableEntry(default_address,
18475e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart                                    default_address,
18575e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart                                    gateway_address,
18675e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart                                    metric,
18775e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart                                    RT_SCOPE_UNIVERSE,
188762bfb8ab200a387fe732ec92423a5f0afe11bcfPrabhu Kaliamoorthi                                    false,
189762bfb8ab200a387fe732ec92423a5f0afe11bcfPrabhu Kaliamoorthi                                    table_id,
190762bfb8ab200a387fe732ec92423a5f0afe11bcfPrabhu Kaliamoorthi                                    RoutingTableEntry::kDefaultTag));
19175e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart}
19275e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart
1933f68bb1e3768969a1db686325ae9a84c8fd06005Paul Stewartbool RoutingTable::ConfigureRoutes(int interface_index,
1941a212a6b98b22ad1d69652bb26a9e94138635476Paul Stewart                                   const IPConfigRefPtr& ipconfig,
195762bfb8ab200a387fe732ec92423a5f0afe11bcfPrabhu Kaliamoorthi                                   uint32_t metric,
196762bfb8ab200a387fe732ec92423a5f0afe11bcfPrabhu Kaliamoorthi                                   uint8_t table_id) {
1973f68bb1e3768969a1db686325ae9a84c8fd06005Paul Stewart  bool ret = true;
1983f68bb1e3768969a1db686325ae9a84c8fd06005Paul Stewart
1993f68bb1e3768969a1db686325ae9a84c8fd06005Paul Stewart  IPAddress::Family address_family = ipconfig->properties().address_family;
2001a212a6b98b22ad1d69652bb26a9e94138635476Paul Stewart  const vector<IPConfig::Route>& routes = ipconfig->properties().routes;
2013f68bb1e3768969a1db686325ae9a84c8fd06005Paul Stewart
2021a212a6b98b22ad1d69652bb26a9e94138635476Paul Stewart  for (const auto& route : routes) {
203c9c31d8497c3f053c2160408cc386010fc125fadRebecca Silberstein    SLOG(this, 3) << "Installing route:"
204c9c31d8497c3f053c2160408cc386010fc125fadRebecca Silberstein                  << " Destination: " << route.host
205c9c31d8497c3f053c2160408cc386010fc125fadRebecca Silberstein                  << " Netmask: " << route.netmask
206c9c31d8497c3f053c2160408cc386010fc125fadRebecca Silberstein                  << " Gateway: " << route.gateway;
2073f68bb1e3768969a1db686325ae9a84c8fd06005Paul Stewart    IPAddress destination_address(address_family);
2083f68bb1e3768969a1db686325ae9a84c8fd06005Paul Stewart    IPAddress source_address(address_family);  // Left as default.
2093f68bb1e3768969a1db686325ae9a84c8fd06005Paul Stewart    IPAddress gateway_address(address_family);
2106db7b24348e69639e19cd6c408388b10d6ee54fePaul Stewart    if (!destination_address.SetAddressFromString(route.host)) {
2113f68bb1e3768969a1db686325ae9a84c8fd06005Paul Stewart      LOG(ERROR) << "Failed to parse host "
2126db7b24348e69639e19cd6c408388b10d6ee54fePaul Stewart                 << route.host;
2133f68bb1e3768969a1db686325ae9a84c8fd06005Paul Stewart      ret = false;
2143f68bb1e3768969a1db686325ae9a84c8fd06005Paul Stewart      continue;
2153f68bb1e3768969a1db686325ae9a84c8fd06005Paul Stewart    }
2166db7b24348e69639e19cd6c408388b10d6ee54fePaul Stewart    if (!gateway_address.SetAddressFromString(route.gateway)) {
2173f68bb1e3768969a1db686325ae9a84c8fd06005Paul Stewart      LOG(ERROR) << "Failed to parse gateway "
2186db7b24348e69639e19cd6c408388b10d6ee54fePaul Stewart                 << route.gateway;
2193f68bb1e3768969a1db686325ae9a84c8fd06005Paul Stewart      ret = false;
2203f68bb1e3768969a1db686325ae9a84c8fd06005Paul Stewart      continue;
2213f68bb1e3768969a1db686325ae9a84c8fd06005Paul Stewart    }
2223f68bb1e3768969a1db686325ae9a84c8fd06005Paul Stewart    destination_address.set_prefix(
2236db7b24348e69639e19cd6c408388b10d6ee54fePaul Stewart        IPAddress::GetPrefixLengthFromMask(address_family, route.netmask));
2243f68bb1e3768969a1db686325ae9a84c8fd06005Paul Stewart    if (!AddRoute(interface_index,
2253f68bb1e3768969a1db686325ae9a84c8fd06005Paul Stewart                  RoutingTableEntry(destination_address,
2263f68bb1e3768969a1db686325ae9a84c8fd06005Paul Stewart                                    source_address,
2273f68bb1e3768969a1db686325ae9a84c8fd06005Paul Stewart                                    gateway_address,
2283f68bb1e3768969a1db686325ae9a84c8fd06005Paul Stewart                                    metric,
2293f68bb1e3768969a1db686325ae9a84c8fd06005Paul Stewart                                    RT_SCOPE_UNIVERSE,
230762bfb8ab200a387fe732ec92423a5f0afe11bcfPrabhu Kaliamoorthi                                    false,
231762bfb8ab200a387fe732ec92423a5f0afe11bcfPrabhu Kaliamoorthi                                    table_id,
232762bfb8ab200a387fe732ec92423a5f0afe11bcfPrabhu Kaliamoorthi                                    RoutingTableEntry::kDefaultTag))) {
2333f68bb1e3768969a1db686325ae9a84c8fd06005Paul Stewart      ret = false;
2343f68bb1e3768969a1db686325ae9a84c8fd06005Paul Stewart    }
2353f68bb1e3768969a1db686325ae9a84c8fd06005Paul Stewart  }
2363f68bb1e3768969a1db686325ae9a84c8fd06005Paul Stewart  return ret;
2373f68bb1e3768969a1db686325ae9a84c8fd06005Paul Stewart}
2383f68bb1e3768969a1db686325ae9a84c8fd06005Paul Stewart
239fb46caf4f23a41e73dfd87547121b5fb0230295aThieu Levoid RoutingTable::FlushRoutes(int interface_index) {
240c9c31d8497c3f053c2160408cc386010fc125fadRebecca Silberstein  SLOG(this, 2) << __func__;
24175e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart
2426db7b24348e69639e19cd6c408388b10d6ee54fePaul Stewart  auto table = tables_.find(interface_index);
24375e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart  if (table == tables_.end()) {
24475e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart    return;
24575e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart  }
24675e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart
2471a212a6b98b22ad1d69652bb26a9e94138635476Paul Stewart  for (const auto& nent : table->second) {
2486db7b24348e69639e19cd6c408388b10d6ee54fePaul Stewart    ApplyRoute(interface_index, nent, RTNLMessage::kModeDelete, 0);
24975e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart  }
250fb46caf4f23a41e73dfd87547121b5fb0230295aThieu Le  table->second.clear();
25175e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart}
25275e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart
253e93b038972d43fd703b3c68603fb4d02bec6504ePaul Stewartvoid RoutingTable::FlushRoutesWithTag(int tag) {
254c9c31d8497c3f053c2160408cc386010fc125fadRebecca Silberstein  SLOG(this, 2) << __func__;
255e93b038972d43fd703b3c68603fb4d02bec6504ePaul Stewart
2561a212a6b98b22ad1d69652bb26a9e94138635476Paul Stewart  for (auto& table : tables_) {
2576db7b24348e69639e19cd6c408388b10d6ee54fePaul Stewart    for (auto nent = table.second.begin(); nent != table.second.end();) {
258e93b038972d43fd703b3c68603fb4d02bec6504ePaul Stewart      if (nent->tag == tag) {
2596db7b24348e69639e19cd6c408388b10d6ee54fePaul Stewart        ApplyRoute(table.first, *nent, RTNLMessage::kModeDelete, 0);
2606db7b24348e69639e19cd6c408388b10d6ee54fePaul Stewart        nent = table.second.erase(nent);
261e93b038972d43fd703b3c68603fb4d02bec6504ePaul Stewart      } else {
262e93b038972d43fd703b3c68603fb4d02bec6504ePaul Stewart        ++nent;
263e93b038972d43fd703b3c68603fb4d02bec6504ePaul Stewart      }
264e93b038972d43fd703b3c68603fb4d02bec6504ePaul Stewart    }
265e93b038972d43fd703b3c68603fb4d02bec6504ePaul Stewart  }
266e93b038972d43fd703b3c68603fb4d02bec6504ePaul Stewart}
267e93b038972d43fd703b3c68603fb4d02bec6504ePaul Stewart
26875e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewartvoid RoutingTable::ResetTable(int interface_index) {
26975e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart  tables_.erase(interface_index);
27075e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart}
27175e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart
2727fab89734d88724a288e96a9996b15548c5294c7Ben Chanvoid RoutingTable::SetDefaultMetric(int interface_index, uint32_t metric) {
273c9c31d8497c3f053c2160408cc386010fc125fadRebecca Silberstein  SLOG(this, 2) << __func__ << " index " << interface_index
274c9c31d8497c3f053c2160408cc386010fc125fadRebecca Silberstein                << " metric " << metric;
27575e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart
2761a212a6b98b22ad1d69652bb26a9e94138635476Paul Stewart  RoutingTableEntry* entry;
277d4ef677ad36ef34f59529af557adbe77b2c29c80mukesh agrawal  if (GetDefaultRouteInternal(
278d4ef677ad36ef34f59529af557adbe77b2c29c80mukesh agrawal          interface_index, IPAddress::kFamilyIPv4, &entry) &&
279d4ef677ad36ef34f59529af557adbe77b2c29c80mukesh agrawal      entry->metric != metric) {
280c1dec4d5cad7c6ee2cd8dbc4f47e4d30403dcca1Paul Stewart    ReplaceMetric(interface_index, entry, metric);
28175e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart  }
28275e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart
283d4ef677ad36ef34f59529af557adbe77b2c29c80mukesh agrawal  if (GetDefaultRouteInternal(
284d4ef677ad36ef34f59529af557adbe77b2c29c80mukesh agrawal          interface_index, IPAddress::kFamilyIPv6, &entry) &&
285d4ef677ad36ef34f59529af557adbe77b2c29c80mukesh agrawal      entry->metric != metric) {
286c1dec4d5cad7c6ee2cd8dbc4f47e4d30403dcca1Paul Stewart    ReplaceMetric(interface_index, entry, metric);
28775e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart  }
28875e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart}
28975e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart
290f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart// static
2911a212a6b98b22ad1d69652bb26a9e94138635476Paul Stewartbool RoutingTable::ParseRoutingTableMessage(const RTNLMessage& message,
2921a212a6b98b22ad1d69652bb26a9e94138635476Paul Stewart                                            int* interface_index,
2931a212a6b98b22ad1d69652bb26a9e94138635476Paul Stewart                                            RoutingTableEntry* entry) {
294f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart  if (message.type() != RTNLMessage::kTypeRoute ||
295f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart      message.family() == IPAddress::kFamilyUnknown ||
296f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart      !message.HasAttribute(RTA_OIF)) {
297f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart    return false;
29875e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart  }
29975e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart
3001a212a6b98b22ad1d69652bb26a9e94138635476Paul Stewart  const RTNLMessage::RouteStatus& route_status = message.route_status();
30175e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart
302762bfb8ab200a387fe732ec92423a5f0afe11bcfPrabhu Kaliamoorthi  if (route_status.type != RTN_UNICAST) {
303f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart    return false;
30475e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart  }
30575e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart
3067fab89734d88724a288e96a9996b15548c5294c7Ben Chan  uint32_t interface_index_u32 = 0;
307f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart  if (!message.GetAttribute(RTA_OIF).ConvertToCPUUInt32(&interface_index_u32)) {
308f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart    return false;
30975e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart  }
310f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart  *interface_index = interface_index_u32;
31175e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart
3127fab89734d88724a288e96a9996b15548c5294c7Ben Chan  uint32_t metric = 0;
313f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart  if (message.HasAttribute(RTA_PRIORITY)) {
314f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart    message.GetAttribute(RTA_PRIORITY).ConvertToCPUUInt32(&metric);
31575e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart  }
31675e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart
317f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart  IPAddress default_addr(message.family());
31875e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart  default_addr.SetAddressToDefault();
31975e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart
32075e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart  ByteString dst_bytes(default_addr.address());
321f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart  if (message.HasAttribute(RTA_DST)) {
322f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart    dst_bytes = message.GetAttribute(RTA_DST);
32375e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart  }
32475e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart  ByteString src_bytes(default_addr.address());
325f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart  if (message.HasAttribute(RTA_SRC)) {
326f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart    src_bytes = message.GetAttribute(RTA_SRC);
32775e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart  }
32875e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart  ByteString gateway_bytes(default_addr.address());
329f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart  if (message.HasAttribute(RTA_GATEWAY)) {
330f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart    gateway_bytes = message.GetAttribute(RTA_GATEWAY);
331f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart  }
332f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart
333f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart  entry->dst = IPAddress(message.family(), dst_bytes, route_status.dst_prefix);
334f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart  entry->src = IPAddress(message.family(), src_bytes, route_status.src_prefix);
335f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart  entry->gateway = IPAddress(message.family(), gateway_bytes);
336f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart  entry->metric = metric;
337f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart  entry->scope = route_status.scope;
338f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart  entry->from_rtnl = true;
339762bfb8ab200a387fe732ec92423a5f0afe11bcfPrabhu Kaliamoorthi  entry->table = route_status.table;
340f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart
341f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart  return true;
342f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart}
343f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart
3441a212a6b98b22ad1d69652bb26a9e94138635476Paul Stewartvoid RoutingTable::RouteMsgHandler(const RTNLMessage& message) {
345f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart  int interface_index;
346f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart  RoutingTableEntry entry;
347f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart
348f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart  if (!ParseRoutingTableMessage(message, &interface_index, &entry)) {
349f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart    return;
35075e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart  }
35175e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart
352e93b038972d43fd703b3c68603fb4d02bec6504ePaul Stewart  if (!route_queries_.empty() &&
353f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart      message.route_status().protocol == RTPROT_UNSPEC) {
354c9c31d8497c3f053c2160408cc386010fc125fadRebecca Silberstein    SLOG(this, 3) << __func__ << ": Message seq: " << message.seq()
355c9c31d8497c3f053c2160408cc386010fc125fadRebecca Silberstein                  << " mode " << message.mode()
356c9c31d8497c3f053c2160408cc386010fc125fadRebecca Silberstein                  << ", next query seq: " << route_queries_.front().sequence;
357f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart
358f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart    // Purge queries that have expired (sequence number of this message is
359f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart    // greater than that of the head of the route query sequence).  Do the
360f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart    // math in a way that's roll-over independent.
3613a62e235646ec19bee71e8dbee5208282dcd13b5Alex Vakulenko    const auto kuint32max = std::numeric_limits<uint32_t>::max();
362e93b038972d43fd703b3c68603fb4d02bec6504ePaul Stewart    while (route_queries_.front().sequence - message.seq() > kuint32max / 2) {
363f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart      LOG(ERROR) << __func__ << ": Purging un-replied route request sequence "
364e93b038972d43fd703b3c68603fb4d02bec6504ePaul Stewart                 << route_queries_.front().sequence
365f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart                 << " (< " << message.seq() << ")";
366abf6d289b2d29487f0a51b6138a127707a38507aDarin Petkov      route_queries_.pop_front();
367e93b038972d43fd703b3c68603fb4d02bec6504ePaul Stewart      if (route_queries_.empty())
368f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart        return;
369f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart    }
370f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart
3711a212a6b98b22ad1d69652bb26a9e94138635476Paul Stewart    const Query& query = route_queries_.front();
372abf6d289b2d29487f0a51b6138a127707a38507aDarin Petkov    if (query.sequence == message.seq()) {
373abf6d289b2d29487f0a51b6138a127707a38507aDarin Petkov      RoutingTableEntry add_entry(entry);
374abf6d289b2d29487f0a51b6138a127707a38507aDarin Petkov      add_entry.from_rtnl = false;
375abf6d289b2d29487f0a51b6138a127707a38507aDarin Petkov      add_entry.tag = query.tag;
376762bfb8ab200a387fe732ec92423a5f0afe11bcfPrabhu Kaliamoorthi      add_entry.table = query.table_id;
377abf6d289b2d29487f0a51b6138a127707a38507aDarin Petkov      bool added = true;
378abf6d289b2d29487f0a51b6138a127707a38507aDarin Petkov      if (add_entry.gateway.IsDefault()) {
379c9c31d8497c3f053c2160408cc386010fc125fadRebecca Silberstein        SLOG(this, 2) << __func__ << ": Ignoring route result with no gateway "
380c9c31d8497c3f053c2160408cc386010fc125fadRebecca Silberstein                      << "since we don't need to plumb these.";
381bbed76d275058c8f9a42c5c71efdcc1223617bdcPaul Stewart      } else {
382c9c31d8497c3f053c2160408cc386010fc125fadRebecca Silberstein        SLOG(this, 2) << __func__ << ": Adding host route to "
383c9c31d8497c3f053c2160408cc386010fc125fadRebecca Silberstein                      << add_entry.dst.ToString();
384abf6d289b2d29487f0a51b6138a127707a38507aDarin Petkov        added = AddRoute(interface_index, add_entry);
385bbed76d275058c8f9a42c5c71efdcc1223617bdcPaul Stewart      }
386abf6d289b2d29487f0a51b6138a127707a38507aDarin Petkov      if (added && !query.callback.is_null()) {
387c9c31d8497c3f053c2160408cc386010fc125fadRebecca Silberstein        SLOG(this, 2) << "Running query callback.";
388abf6d289b2d29487f0a51b6138a127707a38507aDarin Petkov        query.callback.Run(interface_index, add_entry);
389abf6d289b2d29487f0a51b6138a127707a38507aDarin Petkov      }
390abf6d289b2d29487f0a51b6138a127707a38507aDarin Petkov      route_queries_.pop_front();
391f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart    }
392f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart    return;
393f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart  } else if (message.route_status().protocol != RTPROT_BOOT) {
394f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart    // Responses to route queries come back with a protocol of
395f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart    // RTPROT_UNSPEC.  Otherwise, normal route updates that we are
396f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart    // interested in come with a protocol of RTPROT_BOOT.
397f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart    return;
398f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart  }
39975e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart
4001a212a6b98b22ad1d69652bb26a9e94138635476Paul Stewart  TableEntryVector& table = tables_[interface_index];
4016db7b24348e69639e19cd6c408388b10d6ee54fePaul Stewart  for (auto nent = table.begin(); nent != table.end(); ++nent)  {
40275e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart    if (nent->dst.Equals(entry.dst) &&
40375e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart        nent->src.Equals(entry.src) &&
40475e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart        nent->gateway.Equals(entry.gateway) &&
40575e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart        nent->scope == entry.scope) {
406f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart      if (message.mode() == RTNLMessage::kModeDelete &&
407c1dec4d5cad7c6ee2cd8dbc4f47e4d30403dcca1Paul Stewart          nent->metric == entry.metric) {
40875e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart        table.erase(nent);
409f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart      } else if (message.mode() == RTNLMessage::kModeAdd) {
41075e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart        nent->from_rtnl = true;
41175e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart        nent->metric = entry.metric;
41275e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart      }
41375e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart      return;
41475e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart    }
41575e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart  }
41675e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart
417f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart  if (message.mode() == RTNLMessage::kModeAdd) {
418c9c31d8497c3f053c2160408cc386010fc125fadRebecca Silberstein    SLOG(this, 2) << __func__ << " adding"
419c9c31d8497c3f053c2160408cc386010fc125fadRebecca Silberstein                  << " destination " << entry.dst.ToString()
420c9c31d8497c3f053c2160408cc386010fc125fadRebecca Silberstein                  << " index " << interface_index
421c9c31d8497c3f053c2160408cc386010fc125fadRebecca Silberstein                  << " gateway " << entry.gateway.ToString()
422c9c31d8497c3f053c2160408cc386010fc125fadRebecca Silberstein                  << " metric " << entry.metric;
42375e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart    table.push_back(entry);
42475e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart  }
42575e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart}
42675e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart
4277fab89734d88724a288e96a9996b15548c5294c7Ben Chanbool RoutingTable::ApplyRoute(uint32_t interface_index,
4281a212a6b98b22ad1d69652bb26a9e94138635476Paul Stewart                              const RoutingTableEntry& entry,
4299a908080fc2a72dbf06f995b878fc8a3693b725aPaul Stewart                              RTNLMessage::Mode mode,
43075e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart                              unsigned int flags) {
431c9c31d8497c3f053c2160408cc386010fc125fadRebecca Silberstein  SLOG(this, 2) << base::StringPrintf(
432fad4a0b7e55dd82d3815ee96862b6e546727eb6eBen Chan      "%s: dst %s/%d src %s/%d index %d mode %d flags 0x%x",
433fad4a0b7e55dd82d3815ee96862b6e546727eb6eBen Chan      __func__, entry.dst.ToString().c_str(), entry.dst.prefix(),
434fad4a0b7e55dd82d3815ee96862b6e546727eb6eBen Chan      entry.src.ToString().c_str(), entry.src.prefix(),
435fad4a0b7e55dd82d3815ee96862b6e546727eb6eBen Chan      interface_index, mode, flags);
43675e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart
437f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart  RTNLMessage message(
4389a908080fc2a72dbf06f995b878fc8a3693b725aPaul Stewart      RTNLMessage::kTypeRoute,
43975e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart      mode,
440e613202d36e3bfb06a40eea1888694413210ef7ePaul Stewart      NLM_F_REQUEST | flags,
44175e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart      0,
44275e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart      0,
44375e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart      0,
44475e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart      entry.dst.family());
44575e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart
446f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart  message.set_route_status(RTNLMessage::RouteStatus(
4479e3fcd7141240bc5efd0bf1513b9e78aa79d90ebPaul Stewart      entry.dst.prefix(),
4489e3fcd7141240bc5efd0bf1513b9e78aa79d90ebPaul Stewart      entry.src.prefix(),
449762bfb8ab200a387fe732ec92423a5f0afe11bcfPrabhu Kaliamoorthi      entry.table,
45075e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart      RTPROT_BOOT,
45175e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart      entry.scope,
45275e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart      RTN_UNICAST,
45375e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart      0));
45475e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart
455f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart  message.SetAttribute(RTA_DST, entry.dst.address());
45675e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart  if (!entry.src.IsDefault()) {
457f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart    message.SetAttribute(RTA_SRC, entry.src.address());
45875e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart  }
45975e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart  if (!entry.gateway.IsDefault()) {
460f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart    message.SetAttribute(RTA_GATEWAY, entry.gateway.address());
46175e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart  }
462f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart  message.SetAttribute(RTA_PRIORITY,
463f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart                       ByteString::CreateFromCPUUInt32(entry.metric));
464f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart  message.SetAttribute(RTA_OIF,
465f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart                       ByteString::CreateFromCPUUInt32(interface_index));
46675e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart
467f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart  return rtnl_handler_->SendMessage(&message);
46875e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart}
46975e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart
470c1dec4d5cad7c6ee2cd8dbc4f47e4d30403dcca1Paul Stewart// Somewhat surprisingly, the kernel allows you to create multiple routes
471c1dec4d5cad7c6ee2cd8dbc4f47e4d30403dcca1Paul Stewart// to the same destination through the same interface with different metrics.
472c1dec4d5cad7c6ee2cd8dbc4f47e4d30403dcca1Paul Stewart// Therefore, to change the metric on a route, we can't just use the
473c1dec4d5cad7c6ee2cd8dbc4f47e4d30403dcca1Paul Stewart// NLM_F_REPLACE flag by itself.  We have to explicitly remove the old route.
474c1dec4d5cad7c6ee2cd8dbc4f47e4d30403dcca1Paul Stewart// We do so after creating the route at a new metric so there is no traffic
475c1dec4d5cad7c6ee2cd8dbc4f47e4d30403dcca1Paul Stewart// disruption to existing network streams.
4767fab89734d88724a288e96a9996b15548c5294c7Ben Chanvoid RoutingTable::ReplaceMetric(uint32_t interface_index,
4771a212a6b98b22ad1d69652bb26a9e94138635476Paul Stewart                                 RoutingTableEntry* entry,
4787fab89734d88724a288e96a9996b15548c5294c7Ben Chan                                 uint32_t metric) {
479c9c31d8497c3f053c2160408cc386010fc125fadRebecca Silberstein  SLOG(this, 2) << __func__ << " index " << interface_index
480c9c31d8497c3f053c2160408cc386010fc125fadRebecca Silberstein                << " metric " << metric;
481d4ef677ad36ef34f59529af557adbe77b2c29c80mukesh agrawal  RoutingTableEntry new_entry = *entry;
482c1dec4d5cad7c6ee2cd8dbc4f47e4d30403dcca1Paul Stewart  new_entry.metric = metric;
483c1dec4d5cad7c6ee2cd8dbc4f47e4d30403dcca1Paul Stewart  // First create the route at the new metric.
484c1dec4d5cad7c6ee2cd8dbc4f47e4d30403dcca1Paul Stewart  ApplyRoute(interface_index, new_entry, RTNLMessage::kModeAdd,
485c1dec4d5cad7c6ee2cd8dbc4f47e4d30403dcca1Paul Stewart             NLM_F_CREATE | NLM_F_REPLACE);
486c1dec4d5cad7c6ee2cd8dbc4f47e4d30403dcca1Paul Stewart  // Then delete the route at the old metric.
487d4ef677ad36ef34f59529af557adbe77b2c29c80mukesh agrawal  ApplyRoute(interface_index, *entry, RTNLMessage::kModeDelete, 0);
488d4ef677ad36ef34f59529af557adbe77b2c29c80mukesh agrawal  // Now, update our routing table (via |*entry|) from |new_entry|.
489d4ef677ad36ef34f59529af557adbe77b2c29c80mukesh agrawal  *entry = new_entry;
490c1dec4d5cad7c6ee2cd8dbc4f47e4d30403dcca1Paul Stewart}
491c1dec4d5cad7c6ee2cd8dbc4f47e4d30403dcca1Paul Stewart
49275e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewartbool RoutingTable::FlushCache() {
4931a212a6b98b22ad1d69652bb26a9e94138635476Paul Stewart  static const char* kPaths[2] = { kRouteFlushPath4, kRouteFlushPath6 };
49475e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart  bool ret = true;
49575e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart
496c9c31d8497c3f053c2160408cc386010fc125fadRebecca Silberstein  SLOG(this, 2) << __func__;
49775e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart
49875e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart  for (size_t i = 0; i < arraysize(kPaths); ++i) {
4996fbf64f493a9aae7d743888039c61a57386203dbBen Chan    if (base::WriteFile(FilePath(kPaths[i]), "-1", 2) != 2) {
50075e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart      LOG(ERROR) << base::StringPrintf("Cannot write to route flush file %s",
50175e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart                                       kPaths[i]);
50275e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart      ret = false;
50375e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart    }
50475e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart  }
50575e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart
50675e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart  return ret;
50775e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart}
50875e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart
5091a212a6b98b22ad1d69652bb26a9e94138635476Paul Stewartbool RoutingTable::RequestRouteToHost(const IPAddress& address,
510e93b038972d43fd703b3c68603fb4d02bec6504ePaul Stewart                                      int interface_index,
511abf6d289b2d29487f0a51b6138a127707a38507aDarin Petkov                                      int tag,
5121a212a6b98b22ad1d69652bb26a9e94138635476Paul Stewart                                      const Query::Callback& callback,
513762bfb8ab200a387fe732ec92423a5f0afe11bcfPrabhu Kaliamoorthi                                      uint8_t table_id) {
514e78ec548060d969fecdb488d6fed711d843bba91Paul Stewart  // Make sure we don't get a cached response that is no longer valid.
515e78ec548060d969fecdb488d6fed711d843bba91Paul Stewart  FlushCache();
516e78ec548060d969fecdb488d6fed711d843bba91Paul Stewart
517f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart  RTNLMessage message(
518f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart      RTNLMessage::kTypeRoute,
519f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart      RTNLMessage::kModeQuery,
520f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart      NLM_F_REQUEST,
521f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart      0,
522f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart      0,
523f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart      interface_index,
524f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart      address.family());
525f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart
526f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart  RTNLMessage::RouteStatus status;
527f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart  status.dst_prefix = address.prefix();
528f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart  message.set_route_status(status);
529f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart  message.SetAttribute(RTA_DST, address.address());
530536820ddd33f63e1d95e6e04e1757bd0248bbe38Paul Stewart
531536820ddd33f63e1d95e6e04e1757bd0248bbe38Paul Stewart  if (interface_index != -1) {
532536820ddd33f63e1d95e6e04e1757bd0248bbe38Paul Stewart    message.SetAttribute(RTA_OIF,
533536820ddd33f63e1d95e6e04e1757bd0248bbe38Paul Stewart                         ByteString::CreateFromCPUUInt32(interface_index));
534536820ddd33f63e1d95e6e04e1757bd0248bbe38Paul Stewart  }
535f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart
536f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart  if (!rtnl_handler_->SendMessage(&message)) {
537f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart    return false;
538f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart  }
539f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart
540f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart  // Save the sequence number of the request so we can create a route for
541f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart  // this host when we get a reply.
542762bfb8ab200a387fe732ec92423a5f0afe11bcfPrabhu Kaliamoorthi  route_queries_.push_back(Query(message.seq(), tag, callback, table_id));
543f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart
544f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart  return true;
545f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart}
546f748a36f2cde2b1ac7fc543cc710c81cb431cc2fPaul Stewart
547a016312b7470e124774aec197e3b43bc795637c3Ben Chanbool RoutingTable::CreateBlackholeRoute(int interface_index,
548a6bfe87a2c0bcb68d789473ca10988243229667bBen Chan                                        IPAddress::Family family,
549762bfb8ab200a387fe732ec92423a5f0afe11bcfPrabhu Kaliamoorthi                                        uint32_t metric,
550762bfb8ab200a387fe732ec92423a5f0afe11bcfPrabhu Kaliamoorthi                                        uint8_t table_id) {
551c9c31d8497c3f053c2160408cc386010fc125fadRebecca Silberstein  SLOG(this, 2) << base::StringPrintf(
552a016312b7470e124774aec197e3b43bc795637c3Ben Chan      "%s: index %d family %s metric %d",
553a016312b7470e124774aec197e3b43bc795637c3Ben Chan      __func__, interface_index,
554a016312b7470e124774aec197e3b43bc795637c3Ben Chan      IPAddress::GetAddressFamilyName(family).c_str(), metric);
555a016312b7470e124774aec197e3b43bc795637c3Ben Chan
556a016312b7470e124774aec197e3b43bc795637c3Ben Chan  RTNLMessage message(
557a016312b7470e124774aec197e3b43bc795637c3Ben Chan      RTNLMessage::kTypeRoute,
558a016312b7470e124774aec197e3b43bc795637c3Ben Chan      RTNLMessage::kModeAdd,
559a016312b7470e124774aec197e3b43bc795637c3Ben Chan      NLM_F_REQUEST | NLM_F_CREATE | NLM_F_EXCL,
560a016312b7470e124774aec197e3b43bc795637c3Ben Chan      0,
561a016312b7470e124774aec197e3b43bc795637c3Ben Chan      0,
562a016312b7470e124774aec197e3b43bc795637c3Ben Chan      0,
563a016312b7470e124774aec197e3b43bc795637c3Ben Chan      family);
564a016312b7470e124774aec197e3b43bc795637c3Ben Chan
565a016312b7470e124774aec197e3b43bc795637c3Ben Chan  message.set_route_status(RTNLMessage::RouteStatus(
566a016312b7470e124774aec197e3b43bc795637c3Ben Chan      0,
567a016312b7470e124774aec197e3b43bc795637c3Ben Chan      0,
568762bfb8ab200a387fe732ec92423a5f0afe11bcfPrabhu Kaliamoorthi      table_id,
569a016312b7470e124774aec197e3b43bc795637c3Ben Chan      RTPROT_BOOT,
570a016312b7470e124774aec197e3b43bc795637c3Ben Chan      RT_SCOPE_UNIVERSE,
571a016312b7470e124774aec197e3b43bc795637c3Ben Chan      RTN_BLACKHOLE,
572a016312b7470e124774aec197e3b43bc795637c3Ben Chan      0));
573a016312b7470e124774aec197e3b43bc795637c3Ben Chan
574a016312b7470e124774aec197e3b43bc795637c3Ben Chan  message.SetAttribute(RTA_PRIORITY,
575a016312b7470e124774aec197e3b43bc795637c3Ben Chan                       ByteString::CreateFromCPUUInt32(metric));
576a016312b7470e124774aec197e3b43bc795637c3Ben Chan  message.SetAttribute(RTA_OIF,
577a016312b7470e124774aec197e3b43bc795637c3Ben Chan                       ByteString::CreateFromCPUUInt32(interface_index));
578a016312b7470e124774aec197e3b43bc795637c3Ben Chan
579a016312b7470e124774aec197e3b43bc795637c3Ben Chan  return rtnl_handler_->SendMessage(&message);
580a016312b7470e124774aec197e3b43bc795637c3Ben Chan}
581a016312b7470e124774aec197e3b43bc795637c3Ben Chan
5824a6748d492214afcb7c484668fa8cfd3ad963f10Paul Stewartbool RoutingTable::CreateLinkRoute(int interface_index,
5831a212a6b98b22ad1d69652bb26a9e94138635476Paul Stewart                                   const IPAddress& local_address,
5841a212a6b98b22ad1d69652bb26a9e94138635476Paul Stewart                                   const IPAddress& remote_address,
585762bfb8ab200a387fe732ec92423a5f0afe11bcfPrabhu Kaliamoorthi                                   uint8_t table_id) {
5864a6748d492214afcb7c484668fa8cfd3ad963f10Paul Stewart  if (!local_address.CanReachAddress(remote_address)) {
5874a6748d492214afcb7c484668fa8cfd3ad963f10Paul Stewart    LOG(ERROR) << __func__ << " failed: "
5884a6748d492214afcb7c484668fa8cfd3ad963f10Paul Stewart               << remote_address.ToString() << " is not reachable from "
5894a6748d492214afcb7c484668fa8cfd3ad963f10Paul Stewart               << local_address.ToString();
5904a6748d492214afcb7c484668fa8cfd3ad963f10Paul Stewart    return false;
5914a6748d492214afcb7c484668fa8cfd3ad963f10Paul Stewart  }
5924a6748d492214afcb7c484668fa8cfd3ad963f10Paul Stewart
5934a6748d492214afcb7c484668fa8cfd3ad963f10Paul Stewart  IPAddress default_address(local_address.family());
5944a6748d492214afcb7c484668fa8cfd3ad963f10Paul Stewart  default_address.SetAddressToDefault();
5954a6748d492214afcb7c484668fa8cfd3ad963f10Paul Stewart  IPAddress destination_address(remote_address);
5964a6748d492214afcb7c484668fa8cfd3ad963f10Paul Stewart  destination_address.set_prefix(
5974a6748d492214afcb7c484668fa8cfd3ad963f10Paul Stewart      IPAddress::GetMaxPrefixLength(remote_address.family()));
598c9c31d8497c3f053c2160408cc386010fc125fadRebecca Silberstein  SLOG(this, 2) << "Creating link route to " << destination_address.ToString()
599c9c31d8497c3f053c2160408cc386010fc125fadRebecca Silberstein                << " from " << local_address.ToString()
600c9c31d8497c3f053c2160408cc386010fc125fadRebecca Silberstein                << " on interface index " << interface_index;
6014a6748d492214afcb7c484668fa8cfd3ad963f10Paul Stewart  return AddRoute(interface_index,
6024a6748d492214afcb7c484668fa8cfd3ad963f10Paul Stewart                  RoutingTableEntry(destination_address,
6034a6748d492214afcb7c484668fa8cfd3ad963f10Paul Stewart                                    local_address,
6044a6748d492214afcb7c484668fa8cfd3ad963f10Paul Stewart                                    default_address,
6054a6748d492214afcb7c484668fa8cfd3ad963f10Paul Stewart                                    0,
6064a6748d492214afcb7c484668fa8cfd3ad963f10Paul Stewart                                    RT_SCOPE_LINK,
607762bfb8ab200a387fe732ec92423a5f0afe11bcfPrabhu Kaliamoorthi                                    false,
608762bfb8ab200a387fe732ec92423a5f0afe11bcfPrabhu Kaliamoorthi                                    table_id,
609762bfb8ab200a387fe732ec92423a5f0afe11bcfPrabhu Kaliamoorthi                                    RoutingTableEntry::kDefaultTag));
6104a6748d492214afcb7c484668fa8cfd3ad963f10Paul Stewart}
6114a6748d492214afcb7c484668fa8cfd3ad963f10Paul Stewart
61275e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart}  // namespace shill
613