routing_table.cc revision 9a908080fc2a72dbf06f995b878fc8a3693b725a
175e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart// Copyright (c) 2011 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
2175e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart#include <base/callback_old.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>
2775e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart#include <base/stl_util-inl.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
3675e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewartusing std::string;
3775e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewartusing std::vector;
3875e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart
3975e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewartnamespace shill {
4075e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart
410d2ada3971075e78fb9900d0753c9ad94c15add4Paul Stewartstatic base::LazyInstance<RoutingTable> g_routing_table(
420d2ada3971075e78fb9900d0753c9ad94c15add4Paul Stewart    base::LINKER_INITIALIZED);
430d2ada3971075e78fb9900d0753c9ad94c15add4Paul Stewart
4475e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart// static
4575e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewartconst char RoutingTable::kRouteFlushPath4[] = "/proc/sys/net/ipv4/route/flush";
460d2ada3971075e78fb9900d0753c9ad94c15add4Paul Stewart// static
4775e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewartconst char RoutingTable::kRouteFlushPath6[] = "/proc/sys/net/ipv6/route/flush";
4875e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart
4975e89d2d5ecb3c42a869f485d4483fd2176381c0Paul StewartRoutingTable::RoutingTable()
5075e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart    : route_callback_(NewCallback(this, &RoutingTable::RouteMsgHandler)),
5175e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart      route_listener_(NULL) {
5275e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart  VLOG(2) << __func__;
5375e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart}
5475e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart
5575e89d2d5ecb3c42a869f485d4483fd2176381c0Paul StewartRoutingTable::~RoutingTable() {}
5675e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart
5775e89d2d5ecb3c42a869f485d4483fd2176381c0Paul StewartRoutingTable* RoutingTable::GetInstance() {
580d2ada3971075e78fb9900d0753c9ad94c15add4Paul Stewart  return g_routing_table.Pointer();
5975e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart}
6075e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart
6175e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewartvoid RoutingTable::Start() {
6275e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart  VLOG(2) << __func__;
6375e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart
6475e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart  route_listener_.reset(
6575e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart      new RTNLListener(RTNLHandler::kRequestRoute, route_callback_.get()));
6675e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart  RTNLHandler::GetInstance()->RequestDump(
679a908080fc2a72dbf06f995b878fc8a3693b725aPaul Stewart      RTNLHandler::kRequestRoute);
6875e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart}
6975e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart
7075e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewartvoid RoutingTable::Stop() {
7175e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart  VLOG(2) << __func__;
7275e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart
7375e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart  route_listener_.reset();
7475e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart}
7575e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart
7675e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewartbool RoutingTable::AddRoute(int interface_index,
7775e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart                            const RoutingTableEntry &entry) {
7875e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart  VLOG(2) << __func__;
7975e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart
8075e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart  CHECK(!entry.from_rtnl);
8175e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart  if (!ApplyRoute(interface_index,
8275e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart                  entry,
839a908080fc2a72dbf06f995b878fc8a3693b725aPaul Stewart                  RTNLMessage::kModeAdd,
8475e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart                  NLM_F_CREATE | NLM_F_EXCL)) {
8575e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart    return false;
8675e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart  }
8775e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart  tables_[interface_index].push_back(entry);
8875e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart  return true;
8975e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart}
9075e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart
9175e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewartbool RoutingTable::GetDefaultRoute(int interface_index,
9275e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart                                   IPAddress::Family family,
9375e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart                                   RoutingTableEntry *entry) {
9475e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart  VLOG(2) << __func__;
9575e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart
9675e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart  base::hash_map<int, vector<RoutingTableEntry> >::iterator table =
9775e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart    tables_.find(interface_index);
9875e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart
9975e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart  if (table == tables_.end()) {
10075e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart    return false;
10175e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart  }
10275e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart
10375e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart  vector<RoutingTableEntry>::iterator nent;
10475e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart
10575e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart  for (nent = table->second.begin(); nent != table->second.end(); ++nent) {
10675e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart    if (nent->dst.IsDefault() && nent->dst.family() == family) {
10775e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart      *entry = *nent;
10875e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart      return true;
10975e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart    }
11075e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart  }
11175e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart
11275e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart  return false;
11375e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart}
11475e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart
11575e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewartbool RoutingTable::SetDefaultRoute(int interface_index,
11675e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart                                   const IPConfigRefPtr &ipconfig,
11775e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart                                   uint32 metric) {
11875e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart  const IPConfig::Properties &ipconfig_props = ipconfig->properties();
11975e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart  RoutingTableEntry old_entry;
12075e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart
12175e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart  VLOG(2) << __func__;
12275e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart
12375e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart  IPAddress gateway_address(ipconfig_props.address_family);
12475e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart  if (!gateway_address.SetAddressFromString(ipconfig_props.gateway)) {
12575e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart    return false;
12675e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart  }
12775e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart
12875e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart  if (GetDefaultRoute(interface_index,
12975e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart                      ipconfig_props.address_family,
13075e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart                      &old_entry)) {
13175e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart    if (old_entry.gateway.Equals(gateway_address)) {
13275e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart      if (old_entry.metric != metric) {
13375e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart        old_entry.metric = metric;
1349a908080fc2a72dbf06f995b878fc8a3693b725aPaul Stewart        ApplyRoute(interface_index, old_entry, RTNLMessage::kModeAdd,
13575e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart                   NLM_F_CREATE | NLM_F_REPLACE);
13675e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart      }
13775e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart      return true;
13875e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart    } else {
13975e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart      ApplyRoute(interface_index,
14075e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart                 old_entry,
1419a908080fc2a72dbf06f995b878fc8a3693b725aPaul Stewart                 RTNLMessage::kModeDelete,
14275e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart                 0);
14375e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart    }
14475e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart  }
14575e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart
14675e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart  IPAddress default_address(ipconfig_props.address_family);
14775e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart  default_address.SetAddressToDefault();
14875e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart
14975e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart  return AddRoute(interface_index,
15075e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart                  RoutingTableEntry(default_address,
15175e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart                                    default_address,
15275e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart                                    gateway_address,
15375e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart                                    metric,
15475e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart                                    RT_SCOPE_UNIVERSE,
15575e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart                                    false));
15675e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart}
15775e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart
15875e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewartvoid RoutingTable::FlushRoutes(int interface_index) {
15975e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart  VLOG(2) << __func__;
16075e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart
16175e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart  base::hash_map<int, vector<RoutingTableEntry> >::iterator table =
16275e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart    tables_.find(interface_index);
16375e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart
16475e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart  if (table == tables_.end()) {
16575e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart    return;
16675e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart  }
16775e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart
16875e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart  vector<RoutingTableEntry>::iterator nent;
16975e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart
17075e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart  for (nent = table->second.begin(); nent != table->second.end(); ++nent) {
1719a908080fc2a72dbf06f995b878fc8a3693b725aPaul Stewart    ApplyRoute(interface_index, *nent, RTNLMessage::kModeDelete, 0);
17275e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart  }
17375e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart}
17475e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart
17575e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewartvoid RoutingTable::ResetTable(int interface_index) {
17675e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart  tables_.erase(interface_index);
17775e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart}
17875e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart
17975e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewartvoid RoutingTable::SetDefaultMetric(int interface_index, uint32 metric) {
18075e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart  RoutingTableEntry entry;
18175e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart
18275e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart  VLOG(2) << __func__;
18375e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart
18475e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart  if (GetDefaultRoute(interface_index, IPAddress::kAddressFamilyIPv4, &entry) &&
18575e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart      entry.metric != metric) {
18675e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart    entry.metric = metric;
1879a908080fc2a72dbf06f995b878fc8a3693b725aPaul Stewart    ApplyRoute(interface_index, entry, RTNLMessage::kModeAdd,
18875e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart               NLM_F_CREATE | NLM_F_REPLACE);
18975e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart  }
19075e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart
19175e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart  if (GetDefaultRoute(interface_index, IPAddress::kAddressFamilyIPv6, &entry) &&
19275e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart      entry.metric != metric) {
19375e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart    entry.metric = metric;
1949a908080fc2a72dbf06f995b878fc8a3693b725aPaul Stewart    ApplyRoute(interface_index, entry, RTNLMessage::kModeAdd,
19575e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart               NLM_F_CREATE | NLM_F_REPLACE);
19675e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart  }
19775e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart}
19875e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart
1992aa9707f114ab8166f45df5726bf05278df2aef6Chris Masonevoid RoutingTable::RouteMsgHandler(const RTNLMessage &msg) {
20075e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart  VLOG(2) << __func__;
20175e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart
2029a908080fc2a72dbf06f995b878fc8a3693b725aPaul Stewart  if (msg.type() != RTNLMessage::kTypeRoute ||
20375e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart      msg.family() == IPAddress::kAddressFamilyUnknown ||
20475e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart      !msg.HasAttribute(RTA_OIF)) {
20575e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart    return;
20675e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart  }
20775e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart
20875e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart  const RTNLMessage::RouteStatus &route_status = msg.route_status();
20975e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart
21075e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart  if (route_status.type != RTN_UNICAST ||
21175e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart      route_status.protocol != RTPROT_BOOT ||
21275e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart      route_status.table != RT_TABLE_MAIN) {
21375e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart    return;
21475e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart  }
21575e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart
21675e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart  uint32 interface_index = 0;
21775e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart  if (!msg.GetAttribute(RTA_OIF).ConvertToCPUUInt32(&interface_index)) {
21875e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart    return;
21975e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart  }
22075e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart
22175e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart  uint32 metric = 0;
22275e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart  if (msg.HasAttribute(RTA_PRIORITY)) {
22375e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart    msg.GetAttribute(RTA_PRIORITY).ConvertToCPUUInt32(&metric);
22475e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart  }
22575e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart
22675e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart  IPAddress default_addr(msg.family());
22775e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart  default_addr.SetAddressToDefault();
22875e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart
22975e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart  ByteString dst_bytes(default_addr.address());
23075e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart  if (msg.HasAttribute(RTA_DST)) {
23175e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart    dst_bytes = msg.GetAttribute(RTA_DST);
23275e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart  }
23375e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart  ByteString src_bytes(default_addr.address());
23475e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart  if (msg.HasAttribute(RTA_SRC)) {
23575e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart    src_bytes = msg.GetAttribute(RTA_SRC);
23675e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart  }
23775e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart  ByteString gateway_bytes(default_addr.address());
23875e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart  if (msg.HasAttribute(RTA_GATEWAY)) {
23975e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart    gateway_bytes = msg.GetAttribute(RTA_GATEWAY);
24075e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart  }
24175e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart
24275e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart  RoutingTableEntry entry(
2439e3fcd7141240bc5efd0bf1513b9e78aa79d90ebPaul Stewart      IPAddress(msg.family(), dst_bytes, route_status.dst_prefix),
2449e3fcd7141240bc5efd0bf1513b9e78aa79d90ebPaul Stewart      IPAddress(msg.family(), src_bytes, route_status.src_prefix),
24575e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart      IPAddress(msg.family(), gateway_bytes),
24675e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart      metric,
24775e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart      route_status.scope,
24875e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart      true);
24975e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart
25075e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart  vector<RoutingTableEntry> &table = tables_[interface_index];
25175e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart  vector<RoutingTableEntry>::iterator nent;
25275e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart  for (nent = table.begin(); nent != table.end(); ++nent) {
25375e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart    if (nent->dst.Equals(entry.dst) &&
25475e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart        nent->src.Equals(entry.src) &&
25575e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart        nent->gateway.Equals(entry.gateway) &&
25675e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart        nent->scope == entry.scope) {
2579a908080fc2a72dbf06f995b878fc8a3693b725aPaul Stewart      if (msg.mode() == RTNLMessage::kModeDelete) {
25875e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart        table.erase(nent);
25975e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart      } else {
26075e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart        nent->from_rtnl = true;
26175e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart        nent->metric = entry.metric;
26275e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart      }
26375e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart      return;
26475e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart    }
26575e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart  }
26675e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart
2679a908080fc2a72dbf06f995b878fc8a3693b725aPaul Stewart  if (msg.mode() == RTNLMessage::kModeAdd) {
26875e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart    table.push_back(entry);
26975e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart  }
27075e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart}
27175e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart
27275e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewartbool RoutingTable::ApplyRoute(uint32 interface_index,
27375e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart                              const RoutingTableEntry &entry,
2749a908080fc2a72dbf06f995b878fc8a3693b725aPaul Stewart                              RTNLMessage::Mode mode,
27575e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart                              unsigned int flags) {
27675e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart  VLOG(2) << base::StringPrintf("%s: index %d mode %d flags 0x%x",
27775e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart                                __func__, interface_index, mode, flags);
27875e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart
27975e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart  RTNLMessage msg(
2809a908080fc2a72dbf06f995b878fc8a3693b725aPaul Stewart      RTNLMessage::kTypeRoute,
28175e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart      mode,
282e613202d36e3bfb06a40eea1888694413210ef7ePaul Stewart      NLM_F_REQUEST | flags,
28375e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart      0,
28475e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart      0,
28575e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart      0,
28675e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart      entry.dst.family());
28775e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart
28875e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart  msg.set_route_status(RTNLMessage::RouteStatus(
2899e3fcd7141240bc5efd0bf1513b9e78aa79d90ebPaul Stewart      entry.dst.prefix(),
2909e3fcd7141240bc5efd0bf1513b9e78aa79d90ebPaul Stewart      entry.src.prefix(),
29175e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart      RT_TABLE_MAIN,
29275e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart      RTPROT_BOOT,
29375e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart      entry.scope,
29475e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart      RTN_UNICAST,
29575e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart      0));
29675e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart
29775e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart  msg.SetAttribute(RTA_DST, entry.dst.address());
29875e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart  if (!entry.src.IsDefault()) {
29975e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart    msg.SetAttribute(RTA_SRC, entry.src.address());
30075e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart  }
30175e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart  if (!entry.gateway.IsDefault()) {
30275e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart    msg.SetAttribute(RTA_GATEWAY, entry.gateway.address());
30375e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart  }
30475e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart  msg.SetAttribute(RTA_PRIORITY, ByteString::CreateFromCPUUInt32(entry.metric));
30575e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart  msg.SetAttribute(RTA_OIF, ByteString::CreateFromCPUUInt32(interface_index));
30675e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart
30775e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart  return RTNLHandler::GetInstance()->SendMessage(&msg);
30875e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart}
30975e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart
31075e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewartbool RoutingTable::FlushCache() {
31175e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart  static const char *kPaths[2] = { kRouteFlushPath4, kRouteFlushPath6 };
31275e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart  bool ret = true;
31375e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart
31475e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart  VLOG(2) << __func__;
31575e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart
31675e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart  for (size_t i = 0; i < arraysize(kPaths); ++i) {
31775e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart    if (file_util::WriteFile(FilePath(kPaths[i]), "-1", 2) != 2) {
31875e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart      LOG(ERROR) << base::StringPrintf("Cannot write to route flush file %s",
31975e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart                                       kPaths[i]);
32075e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart      ret = false;
32175e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart    }
32275e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart  }
32375e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart
32475e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart  return ret;
32575e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart}
32675e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart
32775e89d2d5ecb3c42a869f485d4483fd2176381c0Paul Stewart}  // namespace shill
328